Repository: ncclient/ncclient

Issue:
XML namespace tag nc:
Hi, I dont think this is an issue with ncclient, but I cant find option to turn off xml namespace tagging.

ncclient sends this RPC,
`<?xml version="1.0" encoding="UTF-8"?>
<nc:rpc xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:cdad1414-956b-47e7-8efc-fee92888475c">
    <nc:get-config>
        <nc:source>
            <nc:running />
        </nc:source>
    </nc:get-config>
</nc:rpc>`

But,
my device (Ericsson Telecom Packet Core elements) do not support xml namespace tags, 
and expect request to be formated as:
`<?xml version="1.0" encoding="UTF-8"?>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:cdad1414-956b-47e7-8efc-fee92888475c">
    <get-config>
        <source>
            <running />
        </source>
    </get-config>
</rpc>`

How can I turn off **nc:** ?

Comments:

Patch:
diff --git a/examples/ericsson_nc_prefix_example.py b/examples/ericsson_nc_prefix_example.py
new file mode 100644
index 0000000..29e569a
--- /dev/null
+++ b/examples/ericsson_nc_prefix_example.py
@@ -0,0 +1,59 @@
+#! /usr/bin/env python
+#
+# Connect to the NETCONF server passed on the command line and
+# set a device_params to turn on/off the namespace prefix "nc".
+# if you want to verify the result, you can print the request that
+# was sent. For brevity and clarity of the examples, we omit proper
+# exception handling.
+#
+# $ ./ericsson_nc_prefix_example.py host username password
+
+import sys, os, warnings
+warnings.simplefilter("ignore", DeprecationWarning)
+from ncclient import manager
+
+
+def ericsson_connect(host, port, user, password, device_params):
+    return manager.connect(host=host,
+                           port=port,
+                           username=user,
+                           password=password,
+                           device_params=device_params,
+                           hostkey_verify-false)
+
+
+def enable_nc_prefix(host, user, password):
+    # add a parameter 'with_ns' to turn on/off 'nc'
+    device_params = {'name': 'ericsson', 'with_ns': True}
+    with ericsson_connect(host,
+                          port=22,
+                          user=user,
+                          password=password,
+                          device_params=device_params) as m:
+
+        ret = m.get_config(source="running").data_xml
+        print(ret)
+
+
+def disable_nc_prefix(host, user, password):
+    # add a parameter 'with_ns' to turn on/off 'nc'
+    device_params = {'name': 'ericsson', 'with_ns': False}
+    with ericsson_connect(host,
+                          port=22,
+                          user=user,
+                          password=password,
+                          device_params=device_params) as m:
+
+        ret = m.get_config(source="running").data_xml
+        print(ret)
+
+
+def demo(host, user, password):
+    enable_nc_prefix(host, user, password)
+    print("#"*50)
+    disable_nc_prefix(host, user, password)
+
+
+if __name__ == '__main__':
+    demo(sys.argv[1], sys.argv[2], sys.argv[3])
+
diff --git a/ncclient/devices/ericsson.py b/ncclient/devices/ericsson.py
new file mode 100644
index 0000000..c161526
--- /dev/null
+++ b/ncclient/devices/ericsson.py
@@ -0,0 +1,45 @@
+"""
+Handler for Ericsson device specific information.
+
+Note that for proper import, the classname has to be:
+
+    "<Devicename>DeviceHandler"
+
+...where <Devicename> is something like "Default", "Ericsson", etc.
+
+All device-specific handlers derive from the DefaultDeviceHandler, which implements the
+generic information needed for interaction with a Netconf server.
+
+"""
+from ncclient.xml_ import BASE_NS_1_0
+from ncclient.operations.errors import OperationError
+from .default import DefaultDeviceHandler
+
+
+class EricssonDeviceHandler(DefaultDeviceHandler):
+    """
+    Ericsson handler for device specific information.
+
+    """
+    _EXEMPT_ERRORS = []
+
+    def __init__(self, device_params):
+        super(EricssonDeviceHandler, self).__init__(device_params)
+
+    def get_xml_base_namespace_dict(self):
+        return {None: BASE_NS_1_0}
+
+    def get_xml_extra_prefix_kwargs(self):
+        d = {}
+        if self.check_device_params() is False:
+            d.update(self.get_xml_base_namespace_dict())
+        return {"nsmap": d}
+
+    def check_device_params(self):
+        value = self.device_params.get('with_ns')
+        if value in [True, False]:
+            return value
+        elif value is None:
+            return False
+        else:
+            raise OperationError('Invalid "with_ns" value: %s' % value)


Test patch:
diff --git a/test/unit/devices/test_ericsson.py b/test/unit/devices/test_ericsson.py
new file mode 100644
index 0000000..1970d5e
--- /dev/null
+++ b/test/unit/devices/test_ericsson.py
@@ -0,0 +1,72 @@
+import unittest
+from ncclient import manager
+from ncclient.devices.ericsson import *
+from ncclient.operations.rpc import *
+from ncclient.capabilities import Capabilities
+import ncclient.transport
+
+class TestEricssonDevice(unittest.TestCase):
+
+    def setUp(self):
+        self.device_handler = manager.make_device_handler({'name': 'ericsson'})
+
+    def test_rpc_default(self):
+        # It is a switch for user to turn on/off "nc" prefix, the "nc" prefix is disable by default
+        session = ncclient.transport.SSHSession(self.device_handler)
+        obj = RPC(session, self.device_handler, raise_mode=RaiseMode.ALL, timeout=0)
+
+        expected = """<?xml version="1.0" encoding="UTF-8"?><rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="%s"><get-config><source><running/></source></get-config></rpc>""" % obj.id
+
+        node = new_ele("get-config")
+        child = sub_ele(node, "source")
+        sub_ele(child, "running")
+
+        rpc_node = obj._wrap(node)
+        self.assertEqual(rpc_node, expected)
+
+    def test_rpc_disable_nc_prefix(self):
+        # It is a switch for user to turn on/off "nc" prefix
+        self.device_handler = manager.make_device_handler({'name': 'ericsson', 'with_ns': False})
+        session = ncclient.transport.SSHSession(self.device_handler)
+        obj = RPC(session, self.device_handler, raise_mode=RaiseMode.ALL, timeout=0)
+
+        expected = """<?xml version="1.0" encoding="UTF-8"?><rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="%s"><get-config><source><running/></source></get-config></rpc>""" % obj.id
+
+        node = new_ele("get-config")
+        child = sub_ele(node, "source")
+        sub_ele(child, "running")
+
+        # It is a switch for user to turn on/off "nc" prefix
+        rpc_node = obj._wrap(node)
+        self.assertEqual(rpc_node, expected)
+
+    def test_rpc_enable_nc_prefix(self):
+        # It is a switch for user to turn on/off "nc" prefix
+        self.device_handler = manager.make_device_handler({'name': 'ericsson', 'with_ns': True})
+        session = ncclient.transport.SSHSession(self.device_handler)
+        obj = RPC(session, self.device_handler, raise_mode=RaiseMode.ALL, timeout=0)
+
+        expected = """<?xml version="1.0" encoding="UTF-8"?><nc:rpc xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="%s"><nc:get-config><nc:source><nc:running/></nc:source></nc:get-config></nc:rpc>""" % obj.id
+
+        node = new_ele("get-config")
+        child = sub_ele(node, "source")
+        sub_ele(child, "running")
+
+        rpc_node = obj._wrap(node)
+        self.assertEqual(rpc_node, expected)
+
+    def test_rpc_enable_nc_prefix_exception(self):
+        # invalid value in "with_ns"
+        self.device_handler = manager.make_device_handler({'name': 'ericsson', 'with_ns': "Invalid_value"})
+        session = ncclient.transport.SSHSession(self.device_handler)
+        obj = RPC(session, self.device_handler, raise_mode=RaiseMode.ALL, timeout=0)
+
+        node = new_ele("get-config")
+        child = sub_ele(node, "source")
+        sub_ele(child, "running")
+
+        self.assertRaises(OperationError, obj._wrap, node)
+
+suite = unittest.TestSuite()
+unittest.TextTestRunner().run(suite)
+