commit 1fca349bb85ea53a792a6009947f29a4af9765dc
Author: Shikhar Bhushan <shikhar@schmizz.net>
Date:   Thu Apr 30 06:11:47 2009 +0000

    * operation stubs * operation classes more elegant (?) * content.NOTIFICATION_NS
    
    
    
    git-svn-id: http://ncclient.googlecode.com/svn/trunk@90 6dbcf712-26ac-11de-a2f3-1373824ab735

diff --git a/ncclient/content.py b/ncclient/content.py
index 7853090..5f90b64 100644
--- a/ncclient/content.py
+++ b/ncclient/content.py
@@ -20,8 +20,8 @@ from xml.etree import cElementTree as ET
 ### Namespace-related ###
 
 BASE_NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
-
-# cisco returns incorrectly namespaced xml
+NOTIFICATION_NS = 'urn:ietf:params:xml:ns:netconf:notification:1.0'
+# and this is BASE_NS according to cisco devices...
 CISCO_BS = 'urn:ietf:params:netconf:base:1.0'
 
 try:
diff --git a/ncclient/operations/__init__.py b/ncclient/operations/__init__.py
index 1e06576..65cde12 100644
--- a/ncclient/operations/__init__.py
+++ b/ncclient/operations/__init__.py
@@ -18,7 +18,7 @@ import logging
 logger = logging.getLogger('ncclient.operations')
 
 from retrieve import Get, GetConfig
-from edit import EditConfig, DeleteConfig
+from edit import EditConfig, CopyConfig, DeleteConfig, Validate, Commit, DiscardChanges
 from session import CloseSession, KillSession
 from lock import Lock, Unlock
 from subscribe import CreateSubscription
@@ -27,6 +27,10 @@ __all__ = [
     'Get',
     'GetConfig',
     'EditConfig',
+    'CopyConfig',
+    'Validate',
+    'Commit',
+    'DiscardChanges',
     'DeleteConfig',
     'Lock',
     'Unlock',
diff --git a/ncclient/operations/edit.py b/ncclient/operations/edit.py
index 955745c..f27f87d 100644
--- a/ncclient/operations/edit.py
+++ b/ncclient/operations/edit.py
@@ -14,9 +14,30 @@
 
 from rpc import RPC
 
+# TODO
+
+
+'''
+notes
+-> editconfig and copyconfig <running> target depends on :writable-running
+-> 
+
+'''
+
 class EditConfig(RPC):
     pass
 
+class CopyConfig(RPC):
+    pass
+
 class DeleteConfig(RPC):
     pass
 
+class Validate(RPC):
+    pass
+
+class Commit(RPC):
+    pass # .confirm() !
+
+class DiscardChanges(RPC):
+    pass
diff --git a/ncclient/operations/lock.py b/ncclient/operations/lock.py
index 20797b9..e9c337c 100644
--- a/ncclient/operations/lock.py
+++ b/ncclient/operations/lock.py
@@ -14,32 +14,38 @@
 
 'Locking-related NETCONF operations'
 
-from rpc import RPC
+# TODO - a context manager around some <target> would be real neat
 
+from rpc import RPC
+from copy import deepcopy
 
 class Lock(RPC):
     
-    def __init__(self, *args, **kwds):
-        RPC.__init__(self, *args, **kwds)
-        self.spec = {
-            'tag': 'lock',
-            'children': { 'tag': 'target', 'children': {'tag': None} }
-            }
+    SPEC = {
+        'tag': 'lock',
+        'children': {
+            'tag': 'target',
+            'children': {'tag': None }
+        }
+    }
     
     def request(self, target='running'):
-        self.spec['children']['children']['tag'] = target
-        self._request(self.spec)
+        spec = deepcopy(Lock.SPEC)
+        spec['children']['children']['tag'] = target
+        return self._request(spec)
 
 
 class Unlock(RPC):
     
-    def __init__(self, *args, **kwds):
-        RPC.__init__(self, *args, **kwds)
-        self.spec = {
-            'tag': 'unlock',
-            'children': { 'tag': 'target', 'children': {'tag': None} }
-            }
+    SPEC = {
+        'tag': 'unlock',
+        'children': {
+            'tag': 'target',
+            'children': {'tag': None }
+        }
+    }
     
     def request(self, target='running'):
-        self.spec['children']['children']['tag'] = target
-        self._request(self.spec)
+        spec = deepcopy(Unlock.SPEC)
+        spec['children']['children']['tag'] = target
+        return self._request(self.spec)
diff --git a/ncclient/operations/reply.py b/ncclient/operations/reply.py
index b66812d..53a42c9 100644
--- a/ncclient/operations/reply.py
+++ b/ncclient/operations/reply.py
@@ -34,6 +34,8 @@ class RPCReply:
         if self._parsed: return
         root = ET.fromstring(self._raw) # <rpc-reply> element
         
+        # check if root is <rpc-reply> ??
+        
         # per rfc 4741 an <ok/> tag is sent when there are no errors or warnings
         oktags = _('ok')
         for oktag in oktags:
diff --git a/ncclient/operations/retrieve.py b/ncclient/operations/retrieve.py
index 6f2f847..c883373 100644
--- a/ncclient/operations/retrieve.py
+++ b/ncclient/operations/retrieve.py
@@ -19,4 +19,3 @@ class Get(RPC):
 
 class GetConfig(RPC):
     pass
-
diff --git a/ncclient/operations/rpc.py b/ncclient/operations/rpc.py
index a3ea1cc..633e85f 100644
--- a/ncclient/operations/rpc.py
+++ b/ncclient/operations/rpc.py
@@ -24,15 +24,22 @@ from ncclient.glue import Listener
 from . import logger
 from reply import RPCReply
 
+
 # Cisco does not include message-id attribute in <rpc-reply> in case of an error.
 # This is messed up however we have to deal with it.
 # So essentially, there can be only one operation at a time if we are talking to
 # a Cisco device.
 
+def cisco_check(session):
+    try:
+        return session.is_remote_cisco
+    except AttributeError:
+        return False
+
 class RPC(object):
     
     def __init__(self, session, async=False):
-        if session.is_remote_cisco and async:
+        if cisco_check(session) and async:
             raise UserWarning('Asynchronous mode not supported for Cisco devices')
         self._session = session
         self._async = async
@@ -120,7 +127,7 @@ class RPCReplyListener(Listener):
         if instance is None:
             instance = object.__new__(cls)
             instance._id2rpc = WeakValueDictionary()
-            instance._cisco = session.is_remote_cisco
+            instance._cisco = cisco_check(session)
             instance._errback = None
             session.add_listener(instance)
         return instance
diff --git a/ncclient/operations/session.py b/ncclient/operations/session.py
index be3dcba..9d4674b 100644
--- a/ncclient/operations/session.py
+++ b/ncclient/operations/session.py
@@ -15,14 +15,13 @@
 'Session-related NETCONF operations'
 
 from rpc import RPC
+from copy import deepcopy
 
 class CloseSession(RPC):
     
     'CloseSession is always synchronous'
     
-    def __init__(self, *args, **kwds):
-        RPC.__init__(self, *args, **kwds)
-        self.spec = { 'tag': 'close-session' }
+    SPEC = { 'tag': 'close-session' }
     
     def _delivery_hook(self):
         if self.reply.ok:
@@ -30,20 +29,19 @@ class CloseSession(RPC):
         self.session.close()
     
     def request(self):
-        return self._request(self.spec)
+        return self._request(CloseSession.SPEC)
 
 
 class KillSession(RPC):
     
-    def __init__(self, *args, **kwds):
-        RPC.__init__(self, *args, **kwds)
-        self.spec = {
-            'tag': 'kill-session',
-            'children': [ { 'tag': 'session-id', 'text': None} ]
-            }
+    SPEC = {
+        'tag': 'kill-session',
+        'children': [ { 'tag': 'session-id', 'text': None} ]
+    }
     
     def request(self, session_id):
-        if not isinstance(session_id, basestring): # just make sure...
+        if not isinstance(session_id, basestring): # just making sure...
             session_id = str(session_id)
-        self.spec['children'][0]['text'] = session_id
-        return self._request(self.spec)
+        spec = deepcopy(SPEC)
+        spec['children'][0]['text'] = session_id
+        return self._request(spec)
diff --git a/ncclient/operations/subscribe.py b/ncclient/operations/subscribe.py
index 675808a..d3e480f 100644
--- a/ncclient/operations/subscribe.py
+++ b/ncclient/operations/subscribe.py
@@ -12,15 +12,21 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TODO...
+
 from rpc import RPC
 
 from ncclient.glue import Listener
-
-from notification import Notification
+from ncclient.content import NOTIFICATION_NS
+from ncclient.content import qualify as _
 
 class CreateSubscription(RPC):    
     
-    pass
+    SPEC = {
+        'tag': _('create-subscription', NOTIFICATION_NS),
+        'startTime': None,
+        'stream': None
+    }
 
 
 class NotificationListener(Listener):
