ncclient.transport pretty much done for now
authorShikhar Bhushan <shikhar@schmizz.net>
Tue, 28 Apr 2009 04:21:56 +0000 (04:21 +0000)
committerShikhar Bhushan <shikhar@schmizz.net>
Tue, 28 Apr 2009 04:21:56 +0000 (04:21 +0000)
git-svn-id: http://ncclient.googlecode.com/svn/trunk@77 6dbcf712-26ac-11de-a2f3-1373824ab735

ncclient/content.py
ncclient/glue.py
ncclient/operations/listeners.py [moved from ncclient/operations/listener.py with 92% similarity]
ncclient/operations/rpc.py
ncclient/transport/__init__.py
ncclient/transport/errors.py
ncclient/transport/hello.py
ncclient/transport/session.py
ncclient/transport/ssh.py

index d78c47e..eb28cf4 100644 (file)
@@ -24,7 +24,6 @@ BASE_NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
 # cisco returns incorrectly namespaced xml
 CISCO_BS = 'urn:ietf:params:netconf:base:1.0'
 
 # cisco returns incorrectly namespaced xml
 CISCO_BS = 'urn:ietf:params:netconf:base:1.0'
 
-# we'd like BASE_NS to be prefixed as "netconf"
 try:
     register_namespace = ET.register_namespace
 except AttributeError:
 try:
     register_namespace = ET.register_namespace
 except AttributeError:
@@ -33,13 +32,13 @@ except AttributeError:
         # cElementTree uses ElementTree's _namespace_map, so that's ok
         ElementTree._namespace_map[uri] = prefix
 
         # cElementTree uses ElementTree's _namespace_map, so that's ok
         ElementTree._namespace_map[uri] = prefix
 
+# we'd like BASE_NS to be prefixed as "netconf"
 register_namespace('netconf', BASE_NS)
 
 qualify = lambda tag, ns: '{%s}%s' % (namespace, tag)
 
 unqualify = lambda tag: tag[tag.rfind('}')+1:]
 
 register_namespace('netconf', BASE_NS)
 
 qualify = lambda tag, ns: '{%s}%s' % (namespace, tag)
 
 unqualify = lambda tag: tag[tag.rfind('}')+1:]
 
-
 ################################################################################
 # Build XML using Python data structures :-)
 
 ################################################################################
 # Build XML using Python data structures :-)
 
index dcd47d9..65f8dff 100644 (file)
@@ -36,10 +36,10 @@ class Subject:
 
     def __init__(self):
         "TODO: docstring"
 
     def __init__(self):
         "TODO: docstring"
+        self._q = Queue()
         self._listeners = set([])
         self._listeners = set([])
-        self._outQ = Queue()
         self._lock = Lock()
         self._lock = Lock()
-
+    
     def _dispatch_received(self, raw):
         "TODO: docstring"
         root = parse_root(raw)
     def _dispatch_received(self, raw):
         "TODO: docstring"
         root = parse_root(raw)
@@ -68,7 +68,7 @@ class Subject:
     def send(self, message):
         "TODO: docstring"
         logger.debug('queueing:%s' % message)
     def send(self, message):
         "TODO: docstring"
         logger.debug('queueing:%s' % message)
-        self._outQ.put(message)
+        self._q.put(message)
 
 
 class Listener:
 
 
 class Listener:
similarity index 92%
rename from ncclient/operations/listener.py
rename to ncclient/operations/listeners.py
index 6a7d353..3ff5d1f 100644 (file)
@@ -16,14 +16,9 @@ from threading import Lock
 from weakref import WeakValueDictionary
 
 from . import logger
 from weakref import WeakValueDictionary
 
 from . import logger
-from ncclient.content.parsers import RootParser
-from ncclient.content.common import qualify as _
-from ncclient.content.common import unqualify as __
-from ncclient.content.common import BASE_NS, CISCO_BS
 
 
-q_rpcreply = [_('rpc-reply', BASE_NS), _('rpc-reply', CISCO_BS)]
 
 
-class SessionListener:
+class RPCReplyListener(Listener):
     
     '''This is the glue between received data and the object it should be
     forwarded to.
     
     '''This is the glue between received data and the object it should be
     forwarded to.
@@ -103,3 +98,8 @@ class SessionListener:
             logger.error('SessionListener.error: %r' % err)
             if self._errback is not None:
                 errback(err)
             logger.error('SessionListener.error: %r' % err)
             if self._errback is not None:
                 errback(err)
+
+
+class NotificationListener(Listener):
+    
+    pass
\ No newline at end of file
index 7af4fdc..ea50f53 100644 (file)
@@ -16,15 +16,20 @@ from threading import Event, Lock
 from uuid import uuid1
 from weakref import WeakKeyDictionary
 
 from uuid import uuid1
 from weakref import WeakKeyDictionary
 
+from . import logger
 from listener import SessionListener
 from ncclient.content.builders import RPCBuilder
 from ncclient.content.parsers import RPCReplyParser
 
 from listener import SessionListener
 from ncclient.content.builders import RPCBuilder
 from ncclient.content.parsers import RPCReplyParser
 
+_listeners = WeakKeyDictionary()
+_lock = Lock()
+
+def get_listener(session):
+    with self._lock:
+        return _listeners.setdefault(session, ReplyListener())
+
 class RPC:
 class RPC:
-    
-    _listeners = WeakKeyDictionary()
-    _lock = Lock()
-    
+        
     def __init__(self, session):
         self._session = session
         self._id = None
     def __init__(self, session):
         self._session = session
         self._id = None
@@ -32,16 +37,10 @@ class RPC:
         self._reply_event = None
     
     @property
         self._reply_event = None
     
     @property
-    def _listener(self):
-        with self._lock:
-            return self._listeners.setdefault(self._session, SessionListener())
     
     
-    def deliver(self, raw):
-        self._reply = RPCReply(raw)
-        self._reply_event.set()
-    
-    def _do_request(self, op, reply_event=None):
+    def _request(self, op):
         self._id = uuid1().urn
         self._id = uuid1().urn
+        self._reply = RPCReply()
         # get the listener instance for this session
         # <rpc-reply> with message id will reach response_cb
         self._listener.register(self._id, self)
         # get the listener instance for this session
         # <rpc-reply> with message id will reach response_cb
         self._listener.register(self._id, self)
@@ -56,7 +55,7 @@ class RPC:
             self._reply_event = Event()
             self._reply_event.wait()
             self._reply.parse()
             self._reply_event = Event()
             self._reply_event.wait()
             self._reply.parse()
-            return self._reply
+        return self._reply
     
     def request(self, *args, **kwds):
         raise NotImplementedError
     
     def request(self, *args, **kwds):
         raise NotImplementedError
@@ -82,10 +81,10 @@ class RPC:
 
 class RPCReply:
     
 
 class RPCReply:
     
-    def __init__(self, raw):
-        self._raw = raw
-        self._parsed = False
-        self._errs = []
+    def __init__(self, event):
+        self._delivery_event = event
+        self._raw = None
+        self._errs = None
     
     def __str__(self):
         return self._raw
     
     def __str__(self):
         return self._raw
@@ -97,6 +96,14 @@ class RPCReply:
                 self._errs.append(RPCError(raw, err_dict))
             self._parsed = True
     
                 self._errs.append(RPCError(raw, err_dict))
             self._parsed = True
     
+    def deliver(self, raw):
+        self._raw = raw
+        self._delivery_event.set()
+    
+    def received(self, timeout=None):
+        self._delivery_event.wait(timeout)
+        return True
+    
     @property
     def raw(self):
         return self._raw
     @property
     def raw(self):
         return self._raw
@@ -153,3 +160,46 @@ class RPCError(Exception): # raise it if you like
     @property
     def info(self):
         return self._dict.get('info', None)
     @property
     def info(self):
         return self._dict.get('info', None)
+
+class Notification:
+    
+    pass
+
+
+
+from builder import TreeBuilder
+from common import BASE_NS
+from common import qualify as _
+
+################################################################################
+
+_ = qualify
+
+def build(msgid, op, encoding='utf-8'):
+    "TODO: docstring"
+    if isinstance(op, basestring):
+        return RPCBuilder.build_from_string(msgid, op, encoding)
+    else:
+        return RPCBuilder.build_from_spec(msgid, op, encoding)
+
+def build_from_spec(msgid, opspec, encoding='utf-8'):
+    "TODO: docstring"
+    spec = {
+        'tag': _('rpc', BASE_NS),
+        'attributes': {'message-id': msgid},
+        'children': opspec
+        }
+    return TreeBuilder(spec).to_string(encoding)
+
+def build_from_string(msgid, opstr, encoding='utf-8'):
+    "TODO: docstring"
+    decl = '<?xml version="1.0" encoding="%s"?>' % encoding
+    doc = (u'''<rpc message-id="%s" xmlns="%s">%s</rpc>''' %
+           (msgid, BASE_NS, opstr)).encode(encoding)
+    return (decl + doc)
+
+################################################################################
+
+# parsing stuff TODO
+
+
index d9ef743..138f0c0 100644 (file)
@@ -15,4 +15,4 @@
 "TODO: docstring"
 
 import logging
 "TODO: docstring"
 
 import logging
-logger = logging.getLogger('ncclient.transport')
\ No newline at end of file
+logger = logging.getLogger('ncclient.transport')
index f559f46..70e91bd 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+"TODO: docstrings"
+
 from ncclient import TransportError
 
 from ncclient import TransportError
 
+class AuthenticationError(TransportError):
+    pass
+
 class SessionCloseError(TransportError):
     
     def __init__(self, in_buf, out_buf=None):
         msg = 'Unexpected session close.'
         if in_buf:
 class SessionCloseError(TransportError):
     
     def __init__(self, in_buf, out_buf=None):
         msg = 'Unexpected session close.'
         if in_buf:
-            msg += ' .. IN_BUFFER: ||%s|| ' % in_buf
+            msg += ' IN_BUFFER: {%s}' % in_buf
         if out_buf:
         if out_buf:
-            msg += ' .. OUT_BUFFER: ||%s||' % out_buf
+            msg += ' OUT_BUFFER: {%s}' % out_buf
         SSHError.__init__(self, msg)
 
 class SSHError(TransportError):
     pass
 
         SSHError.__init__(self, msg)
 
 class SSHError(TransportError):
     pass
 
-class AuthenticationError(TransportError):
-    pass
-
 class SSHUnknownHostError(SSHError):
     
     def __init__(self, hostname, key):
 class SSHUnknownHostError(SSHError):
     
     def __init__(self, hostname, key):
index c837bcf..6b55914 100644 (file)
 
 from xml.etree import cElementTree as ET
 
 
 from xml.etree import cElementTree as ET
 
-from ncclient.content import TreeBuilder
-from ncclient.content import BASE_NS
+from ncclient.glue import Listener
+from ncclient.content import TreeBuilder, BASE_NS
 from ncclient.content import qualify as _
 from ncclient.content import qualify as _
-
+from ncclient.content import unqualify as __
 
 def build(capabilities, encoding='utf-8'):
     "Given a list of capability URI's returns encoded <hello> message"
 
 def build(capabilities, encoding='utf-8'):
     "Given a list of capability URI's returns encoded <hello> message"
index ac75a5e..3987a65 100644 (file)
 # limitations under the License.
 
 from threading import Thread, Event
 # limitations under the License.
 
 from threading import Thread, Event
+
 from ncclient.capabilities import Capabilities, CAPABILITIES
 from ncclient.capabilities import Capabilities, CAPABILITIES
+from ncclient.glue import Subject
+from ncclient.transport import logger
 
 import hello
 
 import hello
-from . import logger
-from ncclient.glue import Subject
 
 class Session(Thread, Subject):
     
 
 class Session(Thread, Subject):
     
index eadf4b5..db1ee05 100644 (file)
@@ -29,7 +29,7 @@ MSG_DELIM = ']]>]]>'
 TICK = 0.1
 
 class SSHSession(Session):
 TICK = 0.1
 
 class SSHSession(Session):
-
+    
     def __init__(self):
         Session.__init__(self)
         self._host_keys = paramiko.HostKeys()
     def __init__(self):
         Session.__init__(self)
         self._host_keys = paramiko.HostKeys()
@@ -74,7 +74,7 @@ class SSHSession(Session):
             else: # if we didn't break out of the loop, full delim was parsed
                 msg_till = buf.tell() - n
                 buf.seek(0)
             else: # if we didn't break out of the loop, full delim was parsed
                 msg_till = buf.tell() - n
                 buf.seek(0)
-                self.dispatch('received', buf.read(msg_till).strip())
+                self._dispatch_received(buf.read(msg_till).strip())
                 buf.seek(n+1, os.SEEK_CUR)
                 rest = buf.read()
                 buf = StringIO()
                 buf.seek(n+1, os.SEEK_CUR)
                 rest = buf.read()
                 buf = StringIO()
@@ -268,11 +268,12 @@ class SSHSession(Session):
         except Exception as e:
             self.close()
             logger.debug('*** broke out of main loop ***')
         except Exception as e:
             self.close()
             logger.debug('*** broke out of main loop ***')
-            self.dispatch('error', e)
+            self._dispatch_error(e)
     
     @property
     def transport(self):
     
     @property
     def transport(self):
-        '''Get underlying paramiko.transport object; this is provided so methods
-        like transport.set_keepalive can be called.
+        '''Get underlying paramiko transport object; this is provided so methods
+        like set_keepalive can be called on it. See paramiko.Transport
+        documentation for details.
         '''
         return self._transport
         '''
         return self._transport