misc; no functional changes
[ncclient] / ncclient / operations / edit.py
index 538e419..f123d50 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from copy import deepcopy
+
 from ncclient import content
 
 from rpc import RPC
 
 import util
 
-"Operations related to configuration editing"
+import logging
+logger = logging.getLogger('ncclient.operations.edit')
+
+
+
+"Operations related to changing device configuration"
 
 class EditConfig(RPC):
-    
-    # tested: no
-    # combed: yes
-    
+
+    # TESTED
+
+    "*<edit-config>* RPC"
+
     SPEC = {'tag': 'edit-config', 'subtree': []}
-    
-    def request(self, target=None, target_url=None, config=None,
-                default_operation=None, test_option=None, error_option=None):
-        util.one_of(target, target_url)
-        spec = EditConfig.SPEC.copy()
+
+    def request(self, target, config, default_operation=None, test_option=None,
+                error_option=None):
+        """
+        :arg target: see :ref:`source_target`
+        :type target: string
+
+        :arg config: a config element in :ref:`dtree`
+        :type config: `string` or `dict` or :class:`~xml.etree.ElementTree.Element`
+
+        :arg default_operation: optional; one of {'merge', 'replace', 'none'}
+        :type default_operation: `string`
+
+        :arg error_option: optional; one of {'stop-on-error', 'continue-on-error', 'rollback-on-error'}. Last option depends on the *:rollback-on-error* capability
+        :type error_option: string
+
+        :arg test_option: optional; one of {'test-then-set', 'set'}. Depends on *:validate* capability.
+        :type test_option: string
+
+        :seealso: :ref:`return`
+        """
+        spec = deepcopy(EditConfig.SPEC)
         subtree = spec['subtree']
-        subtree.append({
-            'tag': 'target',
-            'subtree': util.store_or_url(target, target_url, self._assert)
-            })
-        subtree.append(content.root_ensured(config, 'config'))
-        if default_operation is not None:
+        subtree.append(util.store_or_url('target', target, self._assert))
+        if error_option is not None:
+            if error_option == 'rollback-on-error':
+                self._assert(':rollback-on-error')
             subtree.append({
-                'tag': 'default-operation',
-                'text': default_operation
+                'tag': 'error-option',
+                'text': error_option
                 })
         if test_option is not None:
             self._assert(':validate')
@@ -48,89 +71,115 @@ class EditConfig(RPC):
                 'tag': 'test-option',
                 'text': test_option
                 })
-        if error_option is not None:
-            if error_option == 'rollback-on-error':
-                self._assert(':rollback-on-error')
+        if default_operation is not None:
             subtree.append({
-                'tag': 'error-option',
-                'text': error_option
+                'tag': 'default-operation',
+                'text': default_operation
                 })
-
+        subtree.append(content.validated_element(config, ('config', content.qualify('config'))))
+        return self._request(spec)
 
 class DeleteConfig(RPC):
-    
-    # tested: no
-    # combed: yes
-    
+
+    # TESTED
+
+    "*<delete-config>* RPC"
+
     SPEC = {'tag': 'delete-config', 'subtree': []}
-    
-    def request(self, target=None, target_url=None):
-        spec = DeleteConfig.SPEC.copy()
-        spec['subtree'].append({
-            'tag': 'target',
-            'subtree': util.store_or_url(target, target_url, self._assert)
-            })
+
+    def request(self, target):
+        """
+        :arg target: See :ref:`source_target`
+        :type target: `string` or `dict` or :class:`~xml.etree.ElementTree.Element`
+
+        :seealso: :ref:`return`
+        """
+        spec = deepcopy(DeleteConfig.SPEC)
+        spec['subtree'].append(util.store_or_url('target', target, self._assert))
         return self._request(spec)
 
 
 class CopyConfig(RPC):
-    
-    # tested: no
-    # combed: yes
-    
+
+    # TESTED
+
+    "*<copy-config>* RPC"
+
     SPEC = {'tag': 'copy-config', 'subtree': []}
-    
-    def request(self, source=None, source_url=None, target=None, target_url=None):
-        spec = CopyConfig.SPEC.copy()
-        spec['subtree'].append({
-            'tag': 'source',
-            'subtree': util.store_or_url(source, source_url, self._assert)
-            })
-        spec['subtree'].append({
-            'tag': 'target',
-            'subtree': util.store_or_url(target, target_url, self._assert)
-            })
+
+    def request(self, source, target):
+        """
+        :arg source: See :ref:`source_target`
+        :type source: `string` or `dict` or :class:`~xml.etree.ElementTree.Element`
+
+        :arg target: See :ref:`source_target`
+        :type target: `string` or `dict` or :class:`~xml.etree.ElementTree.Element`
+
+        :seealso: :ref:`return`
+        """
+        spec = deepcopy(CopyConfig.SPEC)
+        spec['subtree'].append(util.store_or_url('target', target, self._assert))
+        spec['subtree'].append(util.store_or_url('source', source, self._assert))
         return self._request(spec)
 
 
 class Validate(RPC):
-    
-    # tested: no
-    # combed: yes
-    
-    'config attr shd not include <config> root'
-    
+
+    # TESTED
+
+    "*<validate>* RPC. Depends on the *:validate* capability."
+
     DEPENDS = [':validate']
-    
+
     SPEC = {'tag': 'validate', 'subtree': []}
-    
-    def request(self, source=None, source_url=None, config=None):
-        util.one_of(source, source_url, config)
-        spec = Validate.SPEC.copy()
-        if config is None:
-            spec['subtree'].append({
-                'tag': 'source',
-                'subtree': util.store_or_url(source, source_url, self._assert)
+
+    def request(self, source):
+        """
+        :arg source: See :ref:`source_target`
+        :type source: `string` or `dict` or :class:`~xml.etree.ElementTree.Element`
+
+        :seealso: :ref:`return`
+        """
+        spec = deepcopy(Validate.SPEC)
+        try:
+            src = content.validated_element(source, ('config', content.qualify('config')))
+        except Exception as e:
+            logger.debug(e)
+            src = util.store_or_url('source', source, self._assert)
+        spec['subtree'].append({
+            'tag': 'source',
+            'subtree': src
             })
-        else:
-            spec['subtree'].append(content.root_ensured(config, 'config'))
         return self._request(spec)
 
 
 class Commit(RPC):
-    
-    # tested: no
-    # combed: yes
-    
+
+    # TESTED
+
+    "*<commit>* RPC. Depends on the *:candidate* capability."
+
     DEPENDS = [':candidate']
-    
+
     SPEC = {'tag': 'commit', 'subtree': []}
-    
+
     def _parse_hook(self):
         pass
-    
+
     def request(self, confirmed=False, timeout=None):
-        spec = SPEC.copy()
+        """
+        Requires *:confirmed-commit* capability if *confirmed* argument is
+        :const:`True`.
+
+        :arg confirmed: optional; request a confirmed commit
+        :type confirmed: `bool`
+
+        :arg timeout: specify timeout for confirmed commit
+        :type timeout: `int`
+
+        :seealso: :ref:`return`
+        """
+        spec = deepcopy(Commit.SPEC)
         if confirmed:
             self._assert(':confirmed-commit')
             spec['subtree'].append({'tag': 'confirmed'})
@@ -142,29 +191,16 @@ class Commit(RPC):
         return self._request(Commit.SPEC)
 
 
-class ConfirmedCommit(Commit):
-    "psuedo-op"
-    
-    # tested: no
-    # combed: yes
-    
-    DEPENDS = [':candidate', ':confirmed-commit']
-    
-    def request(self, timeout=None):
-        "Commit changes; requireing that a confirming commit follow"
-        return Commit.request(self, confirmed=True, timeout=timeout)
-    
-    def confirm(self):
-        "Make the confirming commit"
-        return Commit.request(self, confirmed=True)
+class DiscardChanges(RPC):
 
+    # TESTED
+
+    "*<discard-changes>* RPC. Depends on the *:candidate* capability."
 
-class DiscardChanges(RPC):
-    
-    # tested: no
-    # combed: yes
-    
     DEPENDS = [':candidate']
-    
+
     SPEC = {'tag': 'discard-changes'}
 
+    def request(self):
+        ":seealso: :ref:`return`"
+        return self._request(DiscardChanges.SPEC)