commit ebf2bbc6f6453ebce54858a70b1dc7f110eaa194
Author: Shikhar Bhushan <shikhar@schmizz.net>
Date:   Mon May 11 01:00:18 2009 +0000

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

diff --git a/ncclient/__init__.py b/ncclient/__init__.py
index 8b280b7..e8700b9 100644
--- a/ncclient/__init__.py
+++ b/ncclient/__init__.py
@@ -26,3 +26,5 @@ if sys.version_info < (2, 6):
 
 __version__ = "0.05"
 
+class NCClientError(Exception): pass
+
diff --git a/ncclient/content.py b/ncclient/content.py
index 8d4c8c4..04cf2be 100644
--- a/ncclient/content.py
+++ b/ncclient/content.py
@@ -16,6 +16,9 @@
 
 from xml.etree import cElementTree as ET
 
+from ncclient import NCClientError
+
+class ContentError(NCClientError): pass
 
 ### Namespace-related ###
 
@@ -124,13 +127,13 @@ class XMLConverter:
 
 iselement = ET.iselement
 
-def isdom(x): return True # TODO
+# def isdom(x): return True # TODO
 
-def root_ensured(rep, tag):
+def ensured(rep, req_tag, req_attrs=None):
     if isinstance(rep, basestring):
         rep = ET.XML(rep)
-    err = False
-    if ((iselement(rep) and (rep.tag not in (tag, qualify(tag))) or (isdom(x)))): 
-        raise ArgumentError("Expected root element [%s] not found" % tag)
-    else:
-        return rep
+    if iselement(rep) and (rep.tag not in (req_tag, qualify(req_tag): 
+        raise ContentError("Required root element [%s] not found" % req_tag)
+    if req_attrs is not None:
+        pass # TODO
+    return rep
diff --git a/ncclient/operations/__init__.py b/ncclient/operations/__init__.py
index fc47606..e1098ff 100644
--- a/ncclient/operations/__init__.py
+++ b/ncclient/operations/__init__.py
@@ -16,12 +16,9 @@
 
 from ncclient import NCClientError
 
-class OperationError(NCClientError):
-    pass
-
-class MissingCapabilityError(OperationError):
-    pass
 
+from rpc import RPC, RPCError
+from errors import MissingCapabilityError
 from retrieve import Get, GetConfig
 from edit import EditConfig, CopyConfig, DeleteConfig, Validate, Commit, DiscardChanges
 from session import CloseSession, KillSession
@@ -30,8 +27,8 @@ from subscribe import CreateSubscription
 
 
 __all__ = [
-    'OperationError',
-    'MissingCapabilityError',
+    'RPC',
+    'RPCError',
     'Get',
     'GetConfig',
     'EditConfig',
diff --git a/ncclient/operations/edit.py b/ncclient/operations/edit.py
index c7967eb..538e419 100644
--- a/ncclient/operations/edit.py
+++ b/ncclient/operations/edit.py
@@ -12,16 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from ncclient.content import iselement
+from ncclient import content
 
 from rpc import RPC
 
 import util
 
-
 "Operations related to configuration editing"
 
-
 class EditConfig(RPC):
     
     # tested: no
@@ -38,7 +36,7 @@ class EditConfig(RPC):
             'tag': 'target',
             'subtree': util.store_or_url(target, target_url, self._assert)
             })
-        subtree.append(config)
+        subtree.append(content.root_ensured(config, 'config'))
         if default_operation is not None:
             subtree.append({
                 'tag': 'default-operation',
@@ -115,7 +113,7 @@ class Validate(RPC):
                 'subtree': util.store_or_url(source, source_url, self._assert)
             })
         else:
-            spec['subtree'].append(config)
+            spec['subtree'].append(content.root_ensured(config, 'config'))
         return self._request(spec)
 
 
@@ -169,3 +167,4 @@ class DiscardChanges(RPC):
     DEPENDS = [':candidate']
     
     SPEC = {'tag': 'discard-changes'}
+
diff --git a/ncclient/operations/errors.py b/ncclient/operations/errors.py
new file mode 100644
index 0000000..2c1cf5e
--- /dev/null
+++ b/ncclient/operations/errors.py
@@ -0,0 +1,8 @@
+from ncclient import NCClientError
+
+class OperationError(NCClientError):
+    pass
+
+class MissingCapabilityError(NCClientError):
+    pass
+
diff --git a/ncclient/operations/lock.py b/ncclient/operations/lock.py
index d7a8291..2227db9 100644
--- a/ncclient/operations/lock.py
+++ b/ncclient/operations/lock.py
@@ -14,11 +14,12 @@
 
 'Locking-related NETCONF operations'
 
-from ncclient.rpc import RPC
+from rpc import RPC
 
 class Lock(RPC):
     
     # tested: no
+    # combed: yes
     
     SPEC = {
         'tag': 'lock',
@@ -37,6 +38,7 @@ class Lock(RPC):
 class Unlock(RPC):
     
     # tested: no
+    # combed: yes
     
     SPEC = {
         'tag': 'unlock',
@@ -55,6 +57,7 @@ class Unlock(RPC):
 class LockContext:
     
     # tested: no
+    # combed: yes
     
     def __init__(self, session, target):
         self.session = session
diff --git a/ncclient/operations/retrieve.py b/ncclient/operations/retrieve.py
index 0463490..76b11d4 100644
--- a/ncclient/operations/retrieve.py
+++ b/ncclient/operations/retrieve.py
@@ -12,15 +12,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from ncclient.rpc import RPC, RPCReply
+from rpc import RPC, RPCReply
 
 from ncclient import content
 
 import util
 
-# NOTES
-# - consider class for helping define <filter> for Get/GetConfig??
-
 class GetReply(RPCReply):
     
     'Adds data attribute'
@@ -60,7 +57,7 @@ class Get(RPC):
     def request(self, filter=None):
         spec = Get.SPEC.copy()
         if filter is not None:
-            spec['subtree'].append(content.rootchecked(filter. 'filter', 'type'))
+            spec['subtree'].append(util.build_filter(filter)))
         return self._request(spec)
 
 class GetConfig(RPC):
@@ -87,6 +84,6 @@ class GetConfig(RPC):
             'subtree': util.store_or_url(source, source_url)
             })
         if filter is not None:
-            spec['subtree'].append(content.rootchecked(filter, 'filter', 'type'))
+            spec['subtree'].append(util.build_filter(filter))
         return self._request(spec)
 
diff --git a/ncclient/operations/session.py b/ncclient/operations/session.py
index aedd6c4..47ec5f8 100644
--- a/ncclient/operations/session.py
+++ b/ncclient/operations/session.py
@@ -14,7 +14,7 @@
 
 'Session-related NETCONF operations'
 
-from ncclient.rpc import RPC
+from rpc import RPC
 
 class CloseSession(RPC):
     # tested: no
@@ -22,14 +22,13 @@ class CloseSession(RPC):
     
     SPEC = { 'tag': 'close-session' }
     
-    def _delivery_hook(self):
-        if self.reply.ok:
-            self.session.expect_close()
+    def _delivery_hook(self)
         self.session.close()
 
 
 class KillSession(RPC):
     # tested: no
+    # combed: yes
     
     SPEC = {
         'tag': 'kill-session',
@@ -45,3 +44,4 @@ class KillSession(RPC):
             'text': session_id
         })
         return self._request(spec)
+
diff --git a/ncclient/operations/util.py b/ncclient/operations/util.py
index cbf37b9..a12f633 100644
--- a/ncclient/operations/util.py
+++ b/ncclient/operations/util.py
@@ -16,9 +16,9 @@
 
 from ncclient import OperationError
 from ncclient.content import qualify as _
-from ncclient.content import ensure_root
+from ncclient.content import root_ensured
 
-from ncclient.errors import MissingCapabilityError, ArgumentError
+from errors import MissingCapabilityError
 
 def one_of(*args):
     'Verifies that only one of the arguments is not None'
@@ -31,15 +31,34 @@ def one_of(*args):
                 return
     raise OperationError('Insufficient parameters')
 
-def store_or_url(store, url, capcheck_func=None):
+def store_or_url(store, url, capcheck=None):
     one_of(store, url)
     node = {}
     if store is not None:
         node['tag'] = store
     else:
-        if capcheck_func is not None:
-            capcheck_func(':url') # hmm.. schema check? deem overkill for now
+        if capcheck is not None:
+            capcheck(':url') # hmm.. schema check? deem overkill for now
         node['tag'] = 'url'
         node['text'] = url
     return node
 
+def build_filter(spec, capcheck=None):
+    type = None
+    if isinstance(spec, tuple):
+        type, criteria = tuple
+        rep = {
+            'tag': 'filter',
+            'attributes': {'type': type},
+            'subtree': criteria
+       }
+    else:
+        rep = root_ensure(spec, 'filter', 'type')
+        try:
+            type = rep['type']
+        except KeyError:
+            type = ele[qualify('type'))
+    if type == 'xpath' and capcheck_func is not None:
+        capcheck_func(':xpath')
+    return rep
+
diff --git a/ncclient/transport/errors.py b/ncclient/transport/errors.py
index 56f7c32..9fb6a48 100644
--- a/ncclient/transport/errors.py
+++ b/ncclient/transport/errors.py
@@ -14,10 +14,7 @@
 
 "TODO: docstrings"
 
-from ncclient import NCClientError
-
-class TransportError(NCClientError):
-    pass
+from ncclient.errors import TransportError
 
 class AuthenticationError(TransportError):
     pass
