1 # Copyright 2009 Shikhar Bhushan
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 from xml.etree import cElementTree as ET
17 from ncclient.content import multiqualify as _
18 from ncclient.content import unqualify as __
21 logger = logging.getLogger('ncclient.rpc.reply')
25 def __init__(self, raw):
35 if self._parsed: return
36 root = self._root = ET.fromstring(self._raw) # <rpc-reply> element
38 if __(root.tag) != 'rpc-reply':
39 raise ValueError('Root element is not RPC reply')
42 # per rfc 4741 an <ok/> tag is sent when there are no errors or warnings
45 if root.find(oktag) is not None:
46 logger.debug('parsed [%s]' % oktag)
49 # create RPCError objects from <rpc-error> elements
50 errtags = _('rpc-error')
51 for errtag in errtags:
52 for err in root.getiterator(errtag): # a particular <rpc-error>
53 logger.debug('parsed [%s]' % errtag)
55 for err_detail in err.getchildren(): # <error-type> etc..
56 tag = __(err_detail.tag)
57 d[tag] = (err_detail.text.strip() if tag != 'error-info'
58 else ET.tostring(err_detail, 'utf-8'))
59 self._errors.append(RPCError(d))
64 # TODO: store children in some way...
79 if not self._parsed: self.parse()
80 return not self._errors # empty list => false
84 'List of RPCError objects. Will be empty if no <rpc-error> elements in reply.'
85 if not self._parsed: self.parse()
89 class RPCError(Exception): # raise it if you like
91 def __init__(self, err_dict):
93 if self.message is not None:
94 Exception.__init__(self, self.message)
96 Exception.__init__(self)
100 return self._element.tostring()
104 return self.get('error-type', None)
108 return self.get('error-severity', None)
112 return self.get('error-tag', None)
116 return self.get('error-path', None)
120 return self.get('error-message', None)
124 return self.get('error-info', None)
126 ## dictionary interface
128 __getitem__ = lambda self, key: self._dict.__getitem__(key)
130 __iter__ = lambda self: self._dict.__iter__()
132 __contains__ = lambda self, key: self._dict.__contains__(key)
134 keys = lambda self: self._dict.keys()
136 get = lambda self, key, default: self._dict.get(key, default)
138 iteritems = lambda self: self._dict.iteritems()
140 iterkeys = lambda self: self._dict.iterkeys()
142 itervalues = lambda self: self._dict.itervalues()
144 values = lambda self: self._dict.values()
146 items = lambda self: self._dict.items()
148 __repr__ = lambda self: repr(self._dict)