commit 9667bcb264fe302a8d6b10dd2c4711b6b796ba5d
Author: Shikhar Bhushan <shikhar@schmizz.net>
Date:   Tue Sep 15 15:15:10 2009 +0000

    address issue 9
    
    git-svn-id: http://ncclient.googlecode.com/svn/trunk@173 6dbcf712-26ac-11de-a2f3-1373824ab735

diff --git a/ncclient/operations/rpc.py b/ncclient/operations/rpc.py
index b782901..a43ce35 100644
--- a/ncclient/operations/rpc.py
+++ b/ncclient/operations/rpc.py
@@ -15,13 +15,13 @@
 from threading import Event, Lock
 from uuid import uuid1
 
-from ncclient import xml_
+from ncclient.xml_ import *
 from ncclient.transport import SessionListener
 
 from errors import OperationError, TimeoutExpiredError, MissingCapabilityError
 
 import logging
-logger = logging.getLogger('ncclient.operations.rpc')
+logger = logging.getLogger("ncclient.operations.rpc")
 
 
 class RPCReply:
@@ -55,25 +55,16 @@ class RPCReply:
         """Parse the *<rpc-reply>*"""
         if self._parsed:
             return
-        root = self._root = xml_.xml2ele(self._raw) # <rpc-reply> element
-        # per rfc 4741 an <ok/> tag is sent when there are no errors or warnings
-        ok = xml_.find(root, 'ok', nslist=xml_.NSLIST)
-        if ok is not None:
-            logger.debug('parsed [%s]' % ok.tag)
-        else: # create RPCError objects from <rpc-error> elements
-            error = xml_.find(root, 'rpc-error', nslist=xml_.NSLIST)
+        root = self._root = to_ele(self._raw) # The <rpc-reply> element
+        # Per RFC 4741 an <ok/> tag is sent when there are no errors or warnings
+        ok = root.find(qualify("ok"))
+        if ok is None:
+            # Create RPCError objects from <rpc-error> elements
+            error = root.find(qualify("rpc-error"))
             if error is not None:
-                logger.debug('parsed [%s]' % error.tag)
                 for err in root.getiterator(error.tag):
-                    # process a particular <rpc-error>
-                    d = {}
-                    for err_detail in err.getchildren(): # <error-type> etc..
-                        tag = xml_.unqualify(err_detail.tag)
-                        if tag != 'error-info':
-                            d[tag] = err_detail.text.strip()
-                        else:
-                            d[tag] = xml_.ele2xml(err_detail)
-                    self._errors.append(RPCError(d))
+                    # Process a particular <rpc-error>
+                    self._errors.append(RPCError(err))
         self._parsing_hook(root)
         self._parsed = True
 
@@ -110,13 +101,29 @@ class RPCReply:
         return self._errors
 
 
-class RPCError(OperationError): # raise it if you like
+class RPCError(OperationError):
 
-    """Represents an *<rpc-error>*. It is an instance of :exc:`OperationError`
+    """Represents an *<rpc-error>*. It is a type of :exc:`OperationError`
     and can be raised like any other exception."""
 
-    def __init__(self, err_dict):
-        self._dict = err_dict
+    def __init__(self, err):
+        self._type = None
+        self._severity = None
+        self._info = None
+        self._tag = None
+        self._path = None
+        self._message = None
+        for subele in err:
+            if subele.tag == qualify("error-tag"):
+                self._tag = subele.text
+            elif subele.tag == qualify("error-severity"):
+                self._severity = subele.text
+            elif subele.tag == qualify("error-info"):
+                self._info = subele.text
+            elif subele.tag == qualify("error-path"):
+                self._path = subele.text
+            elif subele.tag == qualify("error-message"):
+                self._message = subele.text
         if self.message is not None:
             OperationError.__init__(self, self.message)
         else:
@@ -125,56 +132,32 @@ class RPCError(OperationError): # raise it if you like
     @property
     def type(self):
         "`string` representing text of *error-type* element"
-        return self.get('error-type', None)
+        return self._type
 
     @property
     def severity(self):
         "`string` representing text of *error-severity* element"
-        return self.get('error-severity', None)
+        return self._severity
 
     @property
     def tag(self):
         "`string` representing text of *error-tag* element"
-        return self.get('error-tag', None)
+        return self._tag
 
     @property
     def path(self):
         "`string` or :const:`None`; representing text of *error-path* element"
-        return self.get('error-path', None)
+        return self._path
 
     @property
     def message(self):
         "`string` or :const:`None`; representing text of *error-message* element"
-        return self.get('error-message', None)
+        return self._message
 
     @property
     def info(self):
         "`string` (XML) or :const:`None`, representing *error-info* element"
-        return self.get('error-info', None)
-
-    ## dictionary interface
-
-    __getitem__ = lambda self, key: self._dict.__getitem__(key)
-
-    __iter__ = lambda self: self._dict.__iter__()
-
-    __contains__ = lambda self, key: self._dict.__contains__(key)
-
-    keys = lambda self: self._dict.keys()
-
-    get = lambda self, key, default: self._dict.get(key, default)
-
-    iteritems = lambda self: self._dict.iteritems()
-
-    iterkeys = lambda self: self._dict.iterkeys()
-
-    itervalues = lambda self: self._dict.itervalues()
-
-    values = lambda self: self._dict.values()
-
-    items = lambda self: self._dict.items()
-
-    __repr__ = lambda self: repr(self._dict)
+        return self._info
 
 
 class RPCReplyListener(SessionListener):
@@ -198,25 +181,26 @@ class RPCReplyListener(SessionListener):
 
     def callback(self, root, raw):
         tag, attrs = root
-        if xml_.unqualify(tag) != 'rpc-reply':
+        if tag != qualify("rpc-reply"):
             return
         for key in attrs: # in the <rpc-reply> attributes
-            if xml_.unqualify(key) == 'message-id': # if we found msgid attr
+            logger.debug("key=%s" % key)
+            if key == "message-id": # if we found msgid attr
                 id = attrs[key] # get the msgid
-                try:
-                    with self._lock:
-                        rpc = self._id2rpc.get(id) # the corresponding rpc
-                        logger.debug('delivering to %r' % rpc)
+                with self._lock:
+                    try:                    
+                        rpc = self._id2rpc[id] # the corresponding rpc
+                        logger.debug("Delivering to %r" % rpc)
                         rpc.deliver_reply(raw)
-                except KeyError:
-                    raise OperationError('Unknown message-id: %s', id)
-                # no catching other exceptions, fail loudly if must
-                else:
-                    # if no error delivering, can del the reference to the RPC
-                    del self._id2rpc[id]
-                    break
+                    except KeyError:
+                        raise OperationError("Unknown message-id: %s", id)
+                    # no catching other exceptions, fail loudly if must
+                    else:
+                        # if no error delivering, can del the reference to the RPC
+                        del self._id2rpc[id]
+                        break
         else:
-            raise OperationError('Could not find "message-id" attribute in <rpc-reply>')
+            raise OperationError("Could not find 'message-id' attribute in <rpc-reply>")
     
     def errback(self, err):
         try:
@@ -244,7 +228,7 @@ class RPC(object):
     # subclass of :class:`RPCReply`.
     REPLY_CLS = RPCReply
 
-    def __init__(self, session, async=False, timeout=None, raise_mode='none'):
+    def __init__(self, session, async=False, timeout=None, raise_mode="none"):
         self._session = session
         try:
             for cap in self.DEPENDS:
@@ -254,25 +238,18 @@ class RPC(object):
         self._async = async
         self._timeout = timeout
         self._raise_mode = raise_mode
-        # keeps things simple instead of having a class attr that has to be locked
-        self._id = uuid1().urn
+        self._id = uuid1().urn # Keeps things simple instead of having a class attr that has to be locked
         self._listener = RPCReplyListener(session)
         self._listener.register(self._id, self)
         self._reply = None
         self._error = None
         self._event = Event()
 
-    def _build(self, opspec):
+    def _build(self, subele):
         # internal
-        spec = {
-            'tag': 'rpc',
-            'attrib': {
-                'xmlns': xml_.BASE_NS_1_0,
-                'message-id': self._id
-                },
-            'subtree': [ opspec ]
-            }
-        return xml_.dtree2xml(spec)
+        ele = new_ele("rpc", {"message-id": self._id}, xmlns=BASE_NS_1_0)
+        ele.append(subele)
+        return to_xml(ele)
 
     def _request(self, op):
         """Subclasses call this method to make the RPC request.
@@ -288,14 +265,15 @@ class RPC(object):
         :type opspec: :obj:`dict` or :obj:`string` or :class:`~xml.etree.ElementTree.Element`
         :rtype: :class:`RPCReply` (sync) or :class:`RPC` (async)
         """
-        logger.debug('request %r with opsepc=%r' % (self, op))
+        logger.info('Requesting %r' % self.__class__.__name__)
         req = self._build(op)
         self._session.send(req)
         if self._async:
-            logger.debug('async, returning')
+            logger.debug('Async request, returning %r', self)
             return self
         else:
-            logger.debug('sync, will wait for timeout=%r' % self._timeout)
+            logger.debug('Sync request, will wait for timeout=%r' %
+                         self._timeout)
             self._event.wait(self._timeout)
             if self._event.isSet():
                 if self._error:
@@ -330,13 +308,11 @@ class RPC(object):
     def deliver_reply(self, raw):
         # internal use
         self._reply = self.REPLY_CLS(raw)
-        #self._delivery_hook() -- usecase?!
         self._event.set()
 
     def deliver_error(self, err):
         # internal use
         self._error = err
-        #self._delivery_hook() -- usecase?!
         self._event.set()
 
     @property
@@ -379,16 +355,17 @@ class RPC(object):
             raise UserWarning('Asynchronous mode not supported for this device/session')
 
     def set_raise_mode(self, mode):
-        assert(choice in ('all', 'errors', 'none'))
+        assert(choice in ("all", "errors", "none"))
         self._raise_mode = mode
 
     def set_timeout(self, timeout):
-        """Set the timeout for synchronous waiting defining how long the RPC
-        request will block on a reply before raising an error."""
+        """Set the timeout for synchronous waiting; defining how long the RPC
+        request will block on a reply before raising an error. Irrelevant for
+        asynchronous usage."""
         self._timeout = timeout
 
     #: Whether this RPC is asynchronous
-    async = property(fget=lambda self: self._async, fset=set_async)
+    is_async = property(fget=lambda self: self._async, fset=set_async)
 
     #: Timeout for synchronous waiting
     timeout = property(fget=lambda self: self._timeout, fset=set_timeout)
