# IMPORT STATEMENTS
import requests
import json
import os
import xmltodict
import pydash
# IMPORT STATEMENTS


class CMS_NBI_Client:

    def __init__(self):
        """
        Description
        -----------
        Class (CMS_NBI_Client) is the main class and contains the config, message_id and session_id variables, login function, logout function, update_config function.

        Attributes
        ----------
        :var self.cms_nbi_config:a nested dict generated by reading the cms_nbi_config.json file located in the CWD of CMSNBIClient.py this var contains the complete config
        :type self.cms_nbi_config:dict

        :var self.cms_netconf_url:this class var contains the full URL for the specific CMS API NBI
        :type self.cms_netconf_url:str

        :var self.message_id:this class var contains the current message_id
        :type self.message_id:str

        :var self.session_id:this class var is generated by a successful login_netconf() call, CMS uses this var in its auth process
        :type self.session_id:str
        """
        # default config data
        self.cms_nbi_config = {}
        config_data = {'config': {'cms_nodes': {'default': {'connection': {'protocol': {'http': 'http', 'https': 'https'}, 'netconf_http_port': '18080', 'netconf_https_port': '18443', 'rest_http_port': '8080', 'http_timeout': 500, 'cms_node_ip': 'localhost'},
                                                            'cms_creds': {'user_nm': 'rootgod', 'pass_wd': 'root'}
                                                            }
                                                },
                                  'cms_netconf_uri': {'e7': '/cmsexc/ex/netconf', 'c7/e3/e5-100': '/cmsweb/nc', 'ae_ont': '/cmsae/ae/netconf'},
                                  'cms_rest_uri': {'devices': '/restnbi/devices?deviceType=', 'region': '/restnbi/region', 'topology': '/restnbi/toplinks', 'profile': '/restnbi/profiles?profileType='}
                                  }
                       }
        # collects the current working directory(cwd) then creates a path for the cms_nbi_config.json file
        cwd = os.getcwd()
        cf_path = os.path.join(cwd, 'cms_nbi_config.json')

        def config_file_checker(data=config_data, config_file_path=cf_path):
        # function to check if the cms_nbi_config.json file exist in the local dir
        # if it doesn't it will dump the default config to the cms_nbi_config.json file in local dir
            if not os.path.exists(config_file_path):
                with open(config_file_path, 'w') as config_file:
                    json.dump(data, config_file, indent=5)
                return True
            else:
                pass

        def config_importer(config_file_path=cf_path):
        # function to import the stored json data at cms_nbi_config.json
            with open(config_file_path, 'r') as cf_file:
                self.cms_nbi_config = json.load(cf_file)['config']

        # try/except clause to check if the config file exist and import the data
        # if cms_nbi_config.json does not exist then it will create it and dump a default config into it
        try:
            config_importer()
        except FileNotFoundError:
            if config_file_checker(data=config_data):
                config_importer()
        # create Cms_nbi_connect vars
        self.cms_netconf_url = None
        self.message_id = None
        self.session_id = None

    def login_netconf(self, message_id=None, protocol='http', port='18080', cms_user_nm='rootgod', cms_user_pass='root', cms_node_ip='localhost', uri='', http_timeout=1):
        """
        Description
        -----------
        function login_netconf() performs the login function as explained in the in pg.14-15 of Calix Management System (CMS) R15.x Northbound Interface API Guide

        Parameter(s)
        ------------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.message_id is None the default of 1 will be used
        :type message_id:str

        :param protocol: this var determines the protocol to use when building the CMS NETCONF NBI URL, CMS supports http/s as described in pg.14 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type protocol:str

        :param port: this var determines the TCP/UDP port to use when building the CMS NETCONF NBI URL, this will be dependent on whether HTTP or HTTPS was chosen, this is described in pg.14 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type port:str

        :param cms_user_nm: this var contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param cms_user_pass: this var contains the plain text password for the provided username, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_pass:str

        :param cms_node_ip: this var contains the FQDN/IP of the targeted CMS node
        :type cms_node_ip:str

        :param uri: this var contains the uri specifying the CMS NBI, this is described in pg.14 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type uri:str

        :param http_timeout: this var contains the http_timeout for the request library, this is in the form of an int
        :type http_timeout:int

        :return: login_netconf() returns a tuple with (False,requests.models.Response object) or (True,'')
        """

        if isinstance(self.cms_netconf_url, type(None)):
            self.cms_netconf_url = f"{protocol}://{cms_node_ip}:{port}{uri}"
        else:
            pass

        if isinstance(message_id, type(None)) and isinstance(self.message_id, type(None)):
            self.message_id = '1'
        elif isinstance(message_id, type(str)):
            self.message_id = message_id
        else:
            pass




        payload = f"""<?xml version="1.0" encoding="UTF-8"?>
                    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
                        <soapenv:Body>
                            <auth message-id="{self.message_id}">
                                <login>
                                    <UserName>{cms_user_nm}</UserName>
                                    <Password>{cms_user_pass}</Password>
                                </login>
                            </auth>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if protocol == 'http':
            try:
                response = requests.post(url=self.cms_netconf_url, headers=headers, data=payload, timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                #debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.post object is returned.
            return False, response

        else:
            # converts the response.content to a dict using xmltodict library
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'Envelope.Body.auth-reply.ResultCode'):
            # test if the resp_dict has a Resultcode key this indicates a response from the server
                if resp_dict['Envelope']['Body']['auth-reply']['ResultCode'] == '0':
                    # Resultcode is 0, the login was successful, the sessionid is saved in memory
                    self.session_id = resp_dict['Envelope']['Body']['auth-reply']['SessionId']
                    return True, resp_dict['Envelope']['Body']['auth-reply']['ResultCode']

                elif resp_dict['Envelope']['Body']['auth-reply']['ResultCode'] == '6':
                    # Resultcode is 6, the login was unsuccessful, returns false and the request.post object
                    return False, response

                else:
                    # other result codes will need to be worked out
                    return False, response
            else:
                # other responses will need to be worked out and coded for
                return False, response

    def logout_netconf(self, message_id=None, protocol='http', port='18080', cms_user_nm='rootgod', cms_node_ip='localhost', uri='', http_timeout=1):
        """
        Description
        -----------
        function logout_netconf() performs the logout function as explained in the in pg.14-16 of Calix Management System (CMS) R15.x Northbound Interface API Guide

        Parameter(s)
        ------------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.message_id is None the default of 1 will be used
        :type message_id:str

        :param protocol: this var determines the protocol to use when building the CMS NETCONF NBI URL, CMS supports http/s as described in pg.14 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type protocol:str

        :param port: this var determines the TCP/UDP port to use when building the CMS NETCONF NBI URL, this will be dependent on whether HTTP or HTTPS was chosen, this is described in pg.14 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type port:str

        :param cms_user_nm: this var contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param cms_node_ip: this var contains the FQDN/IP of the targeted CMS node
        :type cms_node_ip:str

        :param uri: this var contains the uri specifying the CMS NBI, this is described in pg.14 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type uri:str

        :param http_timeout: this var contains the http_timeout for the request library, this is in the form of an int
        :type http_timeout:int

        :return: logout_netconf() returns a tuple with (False,requests.models.Response object) or (True,'')
        """
        if isinstance(message_id, type(None)) and isinstance(self.message_id, type(None)):
            self.message_id = '1'
        elif isinstance(message_id, type(str)):
            self.message_id = message_id
        else:
            pass

        if isinstance(self.cms_netconf_url, type(None)):
            self.cms_netconf_url = f"{protocol}://{cms_node_ip}:{port}{uri}"

        payload = f"""<?xml version="1.0" encoding="UTF-8"?>
                        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
                            <soapenv:Body>
                                <auth message-id="{self.message_id}">
                                    <logout>
                                        <UserName>{cms_user_nm}</UserName>
                                        <SessionId>{self.session_id}</SessionId>
                                    </logout>
                                </auth>
                            </soapenv:Body>
                        </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if protocol == 'http':
            try:
                response = requests.post(url=self.cms_netconf_url, headers=headers, data=payload, timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                #debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response is returned.
            return False, response

        else:
            # converts the response.content to a dict using xmltodict library
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'Envelope.Body.auth-reply.ResultCode'):
            # test if the resp_dict has a Resultcode key this indicates a response from the server
                if resp_dict['Envelope']['Body']['auth-reply']['ResultCode'] == '0':
                    # Resultcode is 0, the logout was successful, this will call a __del__ and destroy the CMS_NBI_Client object in memory
                    # it will also return tuple with True and ResultCode
                    self.session_id = None
                    return True, ''
                elif resp_dict['Envelope']['Body']['auth-reply']['ResultCode'] == '2':
                    # Resultcode is 2, the logout was unsuccessful, this means that the one of the required variables were incorrect,
                    # (session_id or username)
                    return False, response
                else:
                    # other result codes will need to be worked out
                    return False, response
            else:
                # other responses will need to be worked out and coded for
                return False, response

    def update_config(self, pass_wd='', user_nm='', cms_node_ip='', cms_node_name=''):
        """
        Description
        ___________
        function update_config() updates the cms_nbi_config file with the new CMS node data, it will then pull the updated config into the self.cms_nbi_config

        Paremeter(s)
        ------------
        :param pass_wd: this param is the password for the CMS USER ACCOUNT provided in the user_nm param
        :type pass_wd:str

        :param user_nm: this param is the username for the CMS USER ACCOUNT
        :type user_nm:str

        :param cms_node_ip: this param is the FQDN/IP of the CMS node
        :type cms_node_ip:str

        :param cms_node_name: this param is the 'name' of the CMS node
        :type cms_node_name:str

        :return: update_config() currently does not return any objects
        """
        cwd = os.getcwd()
        cf_path = os.path.join(cwd, '../cms_nbi_config.json')

        def config_file_updater(data=self.cms_nbi_config, config_file_path=cf_path):
            # function to check if the cms_nbi_config.json file exist in the local dir
            # if it doesn't it will dump the default config to the cms_nbi_config.json file in local dir
            with open(config_file_path, 'w') as config_file:
                json.dump(data, config_file, indent=5)

        new_cms_node = {'cms_creds': {'pass_wd': pass_wd, 'user_nm': user_nm},
                        'connection': {'cms_node_ip': cms_node_ip,
                                       'http_timeout': 500,
                                       'netconf_http_port': '18080',
                                       'netconf_https_port': '18443',
                                       'protocols': {'http':  'http', 'https': 'https'},
                                       'rest_http_port': '8080'}
                        }

        if isinstance(cms_node_name, str) and len(cms_node_name) >= 1:
            # checks to make sure the cms_node_name is a string and at least 1 char long
            # updated the config in memory then on disk
            self.cms_nbi_config['cms_nodes'][cms_node_name] = new_cms_node
            new_cms_config = {}
            new_cms_config['config'] = self.cms_nbi_config
            config_file_updater(data=new_cms_config)


class Query_E7_Data():

    def __init__(self, cms_nbi_connect_object):
        """
            Description
            -----------
            Class (Query_E7_Data) is the query constructor/posting class for the E7 CMS NETCONF NBI

            Attributes
            ----------
            :var self.cms_nbi_connect_object: accepts object created by the CMS_NBI_Client
            :type self.cms_nbi_connect_object: object
            """
        # Test if the provided object is of a CMS_NBI_Client instance

        if isinstance(cms_nbi_connect_object, CMS_NBI_Client):
            pass
        else:
            raise ValueError(f"""Query_E7_Data accepts a instance of CMS_NBI_Client, a instance of {type(cms_nbi_connect_object)}""")
        self.cms_nbi_connect_object = cms_nbi_connect_object
        # Test if the cms_netconf_url is a str object and contains the e7 uri
        if isinstance(self.cms_nbi_connect_object.cms_netconf_url, str):
            if self.cms_nbi_connect_object.cms_nbi_config['cms_netconf_uri']['e7'] in self.cms_nbi_connect_object.cms_netconf_url:
                pass
            else:
                raise ValueError(f"""uri:{self.cms_nbi_connect_object.cms_nbi_config['cms_netconf_uri']['e7']} was not found in self.cms_nbi_connect_object.cms_netconf_url:{self.cms_nbi_connect_object.cms_netconf_url}""")
        else:
            raise ValueError(f"""self.cms_nbi_connect_object.cms_netconf_url must be a str object""")
        # test if the session_id is a str object
        if isinstance(self.cms_nbi_connect_object.session_id, str):
            if self.cms_nbi_connect_object.session_id.isdigit():
                pass
            else:
                raise ValueError(f"""self.cms_nbi_connect_object.session_id must be a int in a str object""")
        else:
            raise ValueError(f"""self.cms_nbi_connect_object.session_id must be a str object""")

    def system(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1):
        """
        Description
        -----------
        function system() performs a http/xml query to the provided network_nm(e7_node) requesting the <system> object type

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :return: system() will return a nested dict on a successful call and a requests.models.Response object on a failed call
        """

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                            <soapenv:Body>
                                <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                    <get>
                                        <filter type="subtree">
                                            <top>
                                                <object>
                                                    <type>System</type><id/>
                                                </object>
                                            </top>
                                        </filter>
                                    </get>
                                </rpc>
                            </soapenv:Body>
                        </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload, timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)

            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object'):
                return resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']
            else:
                return response

    def system_children(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, after_filter={'': ''}):
        """
        Description
        -----------
        function system_children() performs a http/xml query for the provided network_nm(e7_node) requesting the children of the <system> object type

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param after_filter: this parameter is a dict of the child object to input in the <after> element as shown in pg.18 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type after_filter:dict

        :return: system_children() returns a requests.models.Response object on a failed call, and a nested dict on a successful call
        """
        if 'type' in after_filter.keys():
            _after = f"""\n<after>\n<type>{after_filter['type']}</type>\n<id>\n<{after_filter['type'].lower()}>{after_filter['id']}<{'/'+after_filter['type'].lower()}>\n</id>\n</after>\n"""
        else:
            _after = ""


        payload = f"""
        <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
        <soapenv:Body>
        <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
        <get-config>
        <source>
        <running/>
        </source>
        <filter type="subtree">
        <top>
        <object>
        <type>System</type>
        <id></id>
        <children>{_after}</children>
        </object>
        </top>
        </filter>
        </get-config>
        </rpc>
        </soapenv:Body>
        </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload, timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response is returned.
            return response

        else:
            # The response code is NOT 200, the xmltodict.parse method is called to convert the xml respose to a dictionary.
            resp_dict = xmltodict.parse(response.content)
            # the pydash.object.has method is called to test if the path provided exist,
            # in this case its looking for 'more' as being apart of the path, this indicated there are more children to query
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.more'):
                # set the local variable resp_dict to just the data contained in the child xml tag
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                # this portion of the if statement parses the last value in the dictionary and extracts the <type> and <id> tag values
                last_object_type = [ x for x in resp_dict[len(resp_dict)-1].items()]
                id_key = [key for key in last_object_type[1][1].keys()][0]
                _after_filter_ = {}
                _after_filter_['type'] = last_object_type[0][1]
                _after_filter_['id'] = pydash.get(last_object_type[1][1][id_key], '#text')
                # this portion of the if statement parses the last value in the dictionary and extracts the <type> and <id> tag values
                # this try/except clause test the objectresp_system_childrenvariable, if it doesnt exist it is created and updated
                try:
                    if isinstance(self.resp_system_children, list):
                        self.resp_system_children.extend(resp_dict)
                except:
                    self.resp_system_children = []
                    self.resp_system_children.extend(resp_dict)
                # Recursive method for pulling the rest of the children
                return self.system_children(message_id=message_id, cms_user_nm=cms_user_nm, network_nm=network_nm, http_timeout=http_timeout, after_filter=_after_filter_)
            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.child'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                try:
                    if isinstance(self.resp_system_children, list):
                        self.resp_system_children.extend(resp_dict)
                        resp_system_children = self.resp_system_children
                        del self.resp_system_children
                        return resp_system_children
                except:
                    self.resp_system_children = []
                    self.resp_system_children.extend(resp_dict)
                    resp_system_children = self.resp_system_children
                    del self.resp_system_children
                    return resp_system_children
            else:
                return response

    def system_children_discont(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, after_filter={'': ''}, attr_filter={'': ''}):
        """
        Description
        -----------
        function system_children_discont() performs a http/xml query for the provided network_nm(e7_node) requesting the <Discont> children of the <system> object type

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param after_filter: this parameter is a dict of the child object to input in the <after> element as shown in pg.18 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type after_filter:dict

        :param attr_filter: expects a dictionary with the attr as the key and the attr_val as the value, this is used to perform the attr-filter action as mentioned in pg.40 of the Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type attr_filter:dict

        :return: system_children_discont() will return a requests.models.Response object on a failed call, and a list of nested dict on a successful call
        """
        if 'discont' in after_filter.keys():
            after_filter = f"""<after>
                                <type>DiscOnt</type>
                                    <id>
                                        <discont>{after_filter['discont']}</discont>
                                    </id>
                                </after>"""
        else:
            after_filter = ''

        valid_attr = ['op-stat', 'crit', 'maj', 'min', 'warn', 'info', 'derived-states', 'reg-id', 'prov-reg-id', 'pon', 'model', 'vendor', 'clei', 'ont', 'subscr-id', 'descr', 'curr-sw-vers', 'alt-sw-vers', 'curr-committed', 'mfg-serno', 'product-code', 'curr-cust-vers', 'alt-cust-vers', 'onu-mac', 'mta-mac', 'link-permit-status']
        if '' not in attr_filter.keys():
            _attr_filter = """<attr-filter>"""
            for attr in attr_filter.items():
                if attr[0] in valid_attr:
                    if attr[0] == 'pon':
                        _attr_filter = _attr_filter + f"""<type>GponPort</type>\n<id>\n<shelf>{attr[1]['shelf']}</shelf>\n<card>{attr[1]['card']}</card>\n<gponport>{attr[1]['gponport']}</gponport>\n</id>\n"""
                    else:
                        _attr_filter = _attr_filter + f"""<{attr[0]}>{attr[1]}</{attr[0]}>\n"""
                else:
                    pass
            _attr_filter = _attr_filter + """</attr-filter>"""
        else:
            _attr_filter = """<attr-filter></attr-filter>"""

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                            <soapenv:Body>
                                <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                    <get>
                                        <filter type="subtree">
                                            <top>
                                                <object>
                                                    <type>System</type>
                                                    <id/>
                                                    <children>
                                                        <type>DiscOnt</type>
                                                        {after_filter}
                                                        {_attr_filter}
                                                        <attr-list>op-stat crit maj min warn info derived-states reg-id prov-reg-id pon model vendor clei ont ontprof subscr-id descr curr-sw-vers alt-sw-vers curr-committed mfg-serno product-code curr-cust-vers alt-cust-vers onu-mac mta-mac link-permit-status</attr-list>
                                                    </children>
                                                </object>
                                            </top>
                                        </filter>
                                    </get>
                                </rpc>
                            </soapenv:Body>
                        </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload, timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.more'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                after_filter_ = resp_dict[len(resp_dict)-1]['id']
                try:
                    if isinstance(self.resp_system_children_discont, list):
                        self.resp_system_children_discont.extend(resp_dict)
                except:
                    self.resp_system_children_discont = []
                    self.resp_system_children_discont.extend(resp_dict)
                return self.system_children_discont(message_id=message_id, cms_user_nm=cms_user_nm,
                                                    network_nm=network_nm, http_timeout=http_timeout,
                                                    after_filter=after_filter_, attr_filter=attr_filter)
            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.child'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                try:
                    if isinstance(self.resp_system_children_discont, list):
                        for resp in resp_dict: self.resp_system_children_discont.append(resp)
                        resp_system_discont = self.resp_system_children_discont
                        del self.resp_system_children_discont
                        return resp_system_discont
                except:
                    self.resp_system_children_discont = []
                    self.resp_system_children_discont.append(resp_dict)
                    resp_system_discont = self.resp_system_children_discont
                    del self.resp_system_children_discont
                    return resp_system_discont

            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children'):
                if resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children'] == None:
                    try:
                        isinstance(self.resp_system_children_discont, list)
                        resp_system_discont = self.resp_system_children_discont
                        del self.resp_system_children_discont
                        return resp_system_discont
                    except:
                        return response

                else:
                    return response
            else:
                return response

    def system_children_ontprof(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, after_filter={'': ''}, attr_filter={'': ''}):
        """
        Description
        -----------
        function system_children_ontprof() performs a http/xml query for the provided network_nm(e7_node) requesting the <OntProf> children of the <system> object type

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param after_filter: this parameter is a dict of the child object to input in the <after> element as shown in pg.18 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type after_filter:dict

        :param attr_filter: expects a dictionary with the attr as the key and the attr_val as the value, this is used to perform the attr-filter action as mentioned in pg.40 of the Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type attr_filter:dict

        :return: system_children_ontprof() returns a requests.models.Response object on a failed query and a nested dict on a successful query
        """
        if 'ontprof' in after_filter.keys():
            _after_filter = f"""<after>
                                <type>OntProf</type>
                                    <id>
                                        <ontprof>{after_filter['ontprof']}</ontprof>
                                    </id>
                                </after>"""
        else:
            _after_filter = """"""

        valid_attr = ['name', 'vendor', 'model', 'pots', 'feth', 'geth', 'hpnaeth', 'ds1', 'rfvid', 'hotrfvid', 'eth-oam-capable', 'convert-mcast-capable', 'rg', 'fb', 'default-to-rg']
        if '' not in attr_filter.keys():
            _attr_filter = '''<attr-filter>'''
            for attr in attr_filter.items():
                if attr[0] in valid_attr:
                    _attr_filter = _attr_filter + f'''<{attr[0]}>{attr[1]}</{attr[0]}>'''
            _attr_filter = _attr_filter + '''</attr-filter>'''
        else:
            _attr_filter = '<attr-filter></attr-filter>'
        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <get-config>
                                    <source>
                                        <running/>
                                    </source>
                                    <filter type="subtree">
                                        <top>
                                            <object>
                                                <type>System</type>
                                                <id/>
                                                <children>
                                                    <type>OntProf</type>
                                                    {_after_filter}
                                                    {_attr_filter}
                                                    <attr-list>name vendor model pots feth geth hpnaeth ds1 rfvid hotrfvid eth-oam-capable convert-mcast-capable rg fb default-to-rg</attr-list>
                                                </children>
                                            </object>
                                        </top>
                                    </filter>
                                </get-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.more'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                after_filter_ = resp_dict[len(resp_dict)-1]['id']
                _after_filter_ = {'ontprof': f'{after_filter_["ontprof"]["#text"]}'}
                try:
                    if isinstance(self.resp_system_children_ontprof, list):
                        self.resp_system_children_ontprof.extend(resp_dict)
                except:
                    self.resp_system_children_ontprof = []
                    self.resp_system_children_ontprof.extend(resp_dict)
                return self.system_children_ontprof(message_id=message_id, cms_user_nm=cms_user_nm, network_nm=network_nm, http_timeout=http_timeout, after_filter=_after_filter_, attr_filter=attr_filter)
            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.child'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                try:
                    if isinstance(self.resp_system_children_ontprof, list):
                        if len(resp_dict) > 1:
                            self.resp_system_children_ontprof.extend(resp_dict)
                            resp_system_children_ontprof = self.resp_system_children_ontprof
                            del self.resp_system_children_ontprof
                        else:
                            self.resp_system_children_ontprof.append(resp_dict)
                            resp_system_children_ontprof = self.resp_system_children_ontprof
                            del self.resp_system_children_ontprof
                        return resp_system_children_ontprof
                except:
                    self.resp_system_children_ontprof = []
                    self.resp_system_children_ontprof.append(resp_dict)
                    resp_system_children_ontprof = self.resp_system_children_ontprof
                    del self.resp_system_children_ontprof
                    return resp_system_children_ontprof
            else:
                return response

    def system_children_ontpwe3prof(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, after_filter={'': ''}, attr_filter={'': ''}):
        """
        Description
        -----------
        function system_children_ontpwe3prof() performs a http/xml query for the provided network_nm(e7_node) requesting the <OntPwe3Prof> children of the <System> object type

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param after_filter: this parameter is a dict of the child object to input in the <after> element as shown in pg.18 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type after_filter:dict

        :param attr_filter: expects a dictionary with the attr as the key and the attr_val as the value, this is used to perform the attr-filter action as mentioned in pg.40 of the Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type attr_filter:dict

        :return: system_children_ontpwe3prof() returns a requests.models.Response object on a failed query and a list of nested dict on a successful query
        """
        if '' not in after_filter.keys():
            pass
        else:
            _after_filter = """"""

        valid_attr = ['name', 'tdm-mode']
        if '' not in attr_filter.keys():
            _attr_filter = """<attr-filter>"""
            for attr in attr_filter.items():
                if attr[0] in valid_attr:
                    _attr_filter = _attr_filter + f'''<{attr[0]}>{attr[1]}</{attr[0]}>'''
            _attr_filter = _attr_filter + """</attr-filter>"""
        else:
            _attr_filter = """<attr-filter></attr-filter>"""

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <get-config>
                                    <source>
                                        <running/>
                                    </source>
                                    <filter type="subtree">
                                        <top>
                                            <object>
                                                <type>System</type>
                                                <id/>
                                                <children>
                                                    <type>OntPwe3Prof</type>
                                                    {_after_filter}
                                                    {_attr_filter}
                                                    <attr-list>name tdm-mode</attr-list>
                                                </children>
                                            </object>
                                        </top>
                                    </filter>
                                </get-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.more'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                after_filter_ = resp_dict[len(resp_dict) - 1]['id']
                _after_filter_ = {'ontprof': f'{after_filter_["ontprof"]["#text"]}'}
                try:
                    if isinstance(self.resp_system_children_ontpwe3prof, list):
                        self.resp_system_children_ontpwe3prof.extend(resp_dict)
                except:
                    self.resp_system_children_ontpwe3prof = []
                    self.resp_system_children_ontpwe3prof.extend(resp_dict)
                return self.system_children_ontpwe3prof(message_id=message_id, cms_user_nm=cms_user_nm,
                                                    network_nm=network_nm, http_timeout=http_timeout,
                                                    after_filter=_after_filter_, attr_filter=attr_filter)
            elif pydash.objects.has(resp_dict,'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.child'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                try:
                    if isinstance(self.resp_system_children_ontpwe3prof, list):
                        if len(resp_dict) > 1:
                            self.resp_system_children_ontpwe3prof.extend(resp_dict)
                            resp_system_children_ontpwe3prof = self.resp_system_children_ontpwe3prof
                            del self.resp_system_children_ontpwe3prof
                        else:
                            self.resp_system_children_ontpwe3prof.append(resp_dict)
                            resp_system_children_ontpwe3prof = self.resp_system_children_ontpwe3prof
                            del self.resp_system_children_ontpwe3prof
                        return resp_system_children_ontpwe3prof
                except:
                    self.resp_system_children_ontpwe3prof = []
                    self.resp_system_children_ontpwe3prof.append(resp_dict)
                    resp_system_children_ontpwe3prof = self.resp_system_children_ontpwe3prof
                    del self.resp_system_children_ontpwe3prof
                    return resp_system_children_ontpwe3prof
            else:
                return response

    def system_children_vlan(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, after_filter={'': ''}, attr_filter={'': ''}):
        """
        Description
        -----------
        function system_children_vlan() performs a http/xml query for the provided network_nm(e7_node) requesting the <Vlan> children of the <System> object type

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param after_filter: this parameter is a dict of the child object to input in the <after> element as shown in pg.18 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type after_filter:dict

        :param attr_filter: expects a dictionary with the attr as the key and the attr_val as the value, this is used to perform the attr-filter action as mentioned in pg.40 of the Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type attr_filter:dict

        :return: system_children_vlan() returns a requests.models.Response object on a failed query and a list of nested dict on a successful query
        """
        # After Filter Parser
        if '' not in after_filter.keys():
            _after_filter = f"""<after>{xmltodict.unparse(after_filter,full_document=False)}</after>"""
        else:
            _after_filter = """"""

        # Attr-Filter Parser
        if '' not in attr_filter.keys():
            _attr_filter = f"""<attr-filter>{xmltodict.unparse(attr_filter,full_document=False)}</attr-filter>"""
        else:
            _attr_filter = """"""

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <get-config>
                                    <source>
                                        <running/>
                                    </source>
                                    <filter type="subtree">
                                        <top>
                                            <object>
                                                <type>System</type>
                                                <id/>
                                                <children>
                                                    <type>Vlan</type>
                                                    {_after_filter}
                                                    {_attr_filter}
                                                    <attr-list>name igmp-mode igmp-prof dhcp-mode mac-force-forw ip-src-verify mac-learn ae-ont-discovery pon-tlan pon-hairpin igmp-pbit dhcp-svc-prof option82-enable eth-opt82prof gpon-opt82prof mobility pppoe-prof</attr-list>
                                                </children>
                                            </object>
                                        </top>
                                    </filter>
                                </get-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.more'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                last_entry = {'type': 'Vlan', 'id': {'vlan': resp_dict[len(resp_dict)-1]['id']['vlan']['#text']}}
                try:
                    if isinstance(self.resp_system_children_vlan, list):
                        self.resp_system_children_vlan.extend(resp_dict)
                except:
                    self.resp_system_children_vlan = []
                    self.resp_system_children_vlan.extend(resp_dict)
                return self.system_children_vlan(message_id=message_id, cms_user_nm=cms_user_nm, network_nm=network_nm, http_timeout=http_timeout, after_filter=last_entry, attr_filter=attr_filter)

            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.child'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                try:
                    if isinstance(self.resp_system_children_vlan, list):
                        if isinstance(resp_dict, list):
                            self.resp_system_children_vlan.extend(resp_dict)
                        else:
                            self.resp_system_children_vlan.append(resp_dict)
                except:
                    self.resp_system_children_vlan = []
                    if isinstance(resp_dict, list):
                        self.resp_system_children_vlan.extend(resp_dict)
                    else:
                        self.resp_system_children_vlan.append(resp_dict)
                resp = self.resp_system_children_vlan
                del self.resp_system_children_vlan
                return resp
            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children'):
                if isinstance(self.resp_system_children_vlan, list):
                    resp = self.resp_system_children_vlan
                    del self.resp_system_children_vlan
                    return resp
                else:
                    return response
            else:
                return response

    def ont_children_ethsvc(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, ont_id='', after_filter={'': ''}, attr_filter={'': ''}):
        """
        Description
        -----------
        function ont_children_ethsvc() performs a http/xml query for the provided network_nm(e7_node) requesting the <EthSvc> children of the <ONT> object type

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param after_filter: this parameter is a dict of the child object to input in the <after> element as shown in pg.18 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type after_filter:dict

        :param attr_filter: expects a dictionary with the attr as the key and the attr_val as the value, this is used to perform the attr-filter action as mentioned in pg.40 of the Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type attr_filter:dict

        :return: ont_children_ethsvc() returns a requests.models.Response object on a failed/empty query and a list of nested dict on a successful query


        Example
        -----------
        # ALL EthSvc on the specified ONT_ID
        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1')

        # We can also pass filters to ont_children_ethsvc() function to narrow our query down.
        # --------------LIST OF FILTERS--------------
        # --------KEY--------|--------VALUE--------
        # 'admin'            | 'enabled' or 'disabled' or 'enabled-no-alarms'
        # 'descr'            | 'example_description'
        # 'tag-action'       | {'type': 'SvcTagAction', 'id': {'svctagaction': 'svctagaction_id'}}
        # 'bw-prof'          | {'type': 'BwProf', 'id': {'bwprof': 'bwprof_id'}}
        # 'out-tag'          | 'none' or '2' --------s-tag, ie outer tag of a QinQ frame should be represented as an int str object
        # 'in-tag'           | 'none' or '2' --------c-tag, ie inner tag of a QinQ frame should be represented as an int str object
        # 'mcast-prof'       | None or {'type': 'McastProf', 'id': {'mcastprof': 'mcastprof_id'}}
        # 'pon-cos'          | 'derived' or 'cos-1' through 'cos-4' or 'user-1' through 'user-4' or 'fixed' ----Please reference pg.173 from (Calix Management System (CMS) R15.x Northbound Interface API Guide) && pg.251 from (Calix E-Series (E7 OS R2.5) Engineering and Planning Guide) for more information
        # 'us-cir-override'  | 'none' or '1k' through '2048k' in 64bit increments or '0m' through '2500m'   ----Please reference pg.205-310 from (Calix E-Series (E7 OS R2.5) Engineering and Planning Guide) for more information
        # 'us-pir-override'  | 'none' or '1k' through '2048k' in 64bit increments or '0m' through '2500m'   ----Please reference pg.205-310 from (Calix E-Series (E7 OS R2.5) Engineering and Planning Guide) for more information
        # 'ds-pir-override'  | 'none' or '1k' through '2048k' in 64bit increments or '0m' through '2500m'   ----Please reference pg.205-310 from (Calix E-Series (E7 OS R2.5) Engineering and Planning Guide) for more information
        # 'hot-swap'         | 'enabled' or 'disabled' -----Please reference (Calix E-Series (E7 EXA R3.x) GPON Applications Guide) for more information


        # ------BY ADMIN STATE------
        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'admin': 'enabled'})

        # ------BY EthSvc DESCRIPTION------
        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'descr': 'example_description'})

        # ------BY SvcTagAction ID------
        # Using an SvcTagAction ID of 1
        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'tag-action':
                                                           {'type': 'SvcTagAction',
                                                            'id': {'svctagaction': '1'}}})

        # ------BY BANDWIDTH PROFILE ID------
        # Using an BwProf ID of 1
        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'bw-prof':
                                                           {'type': 'BwProf',
                                                            'id': {'bwprof': '1'}}})

        # ------BY OUTER VLAN TAG------
        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'out-tag': '2'})

        # ------BY INNER VLAN TAG------
        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'in-tag': '2'})

        # ------BY MULTICAST PROFILE ID------
        # Using an McastProf ID of 1
        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'mcast-prof': {'type': 'McastProf',
                                                                      'id': {'mcastprof': '1'}}})

        # Using an None as the Mcast value, this will search for all EthSvc with no McastProf applied
        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'mcast-prof': None})


        # ------BY PON COS------
        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'pon-cos': 'derived'})

        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'pon-cos': 'cos-1'})

        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'pon-cos': 'user-1'})

        query_e7_data.ont_children_ethsvc(message_id='1',
                                          cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                          network_nm='NTWK-Example_Name',
                                          http_timeout=1,
                                          ont_id='1',
                                          attr_filter={'pon-cos': 'fixed'})
        """

        if '' not in after_filter.keys():
            _after_filter = f"""<after>{xmltodict.unparse(after_filter,full_document=False)}</after>"""
        else:
            _after_filter = """"""

        if '' not in attr_filter.keys():
            _attr_filter = f"""<attr-filter>{xmltodict.unparse(attr_filter, full_document=False)}</attr-filter>"""
        else:
            _attr_filter = """<attr-filter></attr-filter>"""

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <get-config>
                                    <source>
                                        <running/>
                                    </source>
                                    <filter type="subtree">
                                        <top>
                                            <object>
                                                <type>Ont</type>
                                                <id>
                                                    <ont>{ont_id}</ont>
                                                </id>
                                                <children>
                                                    <type>EthSvc</type>
                                                        {_after_filter}
                                                        {_attr_filter}
                                                    <attr-list>admin descr tag-action bw-prof out-tag in-tag mcast-prof pon-cos us-cir-override us-pir-override ds-pir-override hot-swap pppoe-force-discard</attr-list>
                                                </children>
                                            </object>
                                        </top>
                                    </filter>
                                </get-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children.more'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']['child']
                last_entry = resp_dict[len(resp_dict)-1]
                __after_filter = {'type': last_entry['type'], 'id': {'ont': last_entry['id']['ont'], 'ontslot': last_entry['id']['ontslot'], 'ontethany': last_entry['id']['ontethany'], 'ethsvc': last_entry['id']['ethsvc']['#text']}}
                try:
                    if isinstance(self.resp_ont_children_ethsvc, list):
                        self.resp_ont_children_ethsvc.extend(resp_dict)
                except:
                    self.resp_ont_children_ethsvc = []
                    self.resp_ont_children_ethsvc.extend(resp_dict)
                return self.ont_children_ethsvc(message_id=message_id, cms_user_nm=cms_user_nm, network_nm=network_nm, http_timeout=http_timeout, ont_id=ont_id, after_filter=__after_filter, attr_filter=attr_filter)
            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object.children'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']['children']
                # Trying to catch NONE type objects and not append them to the list
                if not isinstance(resp_dict, type(None)):
                    try:
                        if isinstance(self.resp_ont_children_ethsvc, list):
                            if isinstance(resp_dict, list):
                                self.resp_ont_children_ethsvc.extend(resp_dict)
                            else:
                                self.resp_ont_children_ethsvc.append(resp_dict)
                    except:
                        self.resp_ont_children_ethsvc = []
                        if isinstance(resp_dict, list):
                            self.resp_ont_children_ethsvc.extend(resp_dict)
                        else:
                            self.resp_ont_children_ethsvc.append(resp_dict)
                else:
                    pass

                try:
                    resp = self.resp_ont_children_ethsvc
                    del self.resp_ont_children_ethsvc
                except:
                    resp = response
                return resp
            else:
                return response

    def ontprof(self,  message_id='1', cms_user_nm='rootgod', network_nm='', ontprof_id='', http_timeout=1):
        """
        Description
        -----------
        function ontprof() performs a http/xml query for the provided network_nm(e7_node) requesting the children of the <OntProf> object type

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param ontprof_id: this parameter identifies the ID of a pre-defined local ONT profile, which can be a custom profile from 1 to 50, or one of the default profile IDs listed in E7 GPON ONT Profile IDs, as described in pg.140 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type ontprof_id:str

        :return: ontprof() will return a requests.models.Response object on a failed query, and a dict on a successful query
        """
        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <get-config>
                                    <source>
                                        <running/>
                                    </source>
                                    <filter type="subtree">
                                        <top>
                                            <object>
                                                <type>OntProf</type>
                                                <id>
                                                    <ontprof>{ontprof_id}</ontprof>
                                                </id>
                                            </object>
                                        </top>
                                    </filter>
                                </get-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""


        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS-NBI-CLIENT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload, timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object'):
                return resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']
            else:
                return response

    def discont(self, message_id='1', cms_user_nm='rootgod', network_nm='', ont_sn='', http_timeout=1):
        """
        Description
        -----------
        function discont() performs a http/xml query for the provided network_nm(e7_node) requesting the child of the <DiscOnt> object type

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param ont_sn: this parameter is the SN of the ont being requested, for calix ONTs this is formed by CXNK+
        :type ont_sn:str

        :return: discont() will return a requests.models.Response object on a failed query, and a dict on a successful query
        """

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <get>
                                    <filter>
                                        <top>
                                            <object>
                                                <type>DiscOnt</type>
                                                <id>
                                                    <discont>{ont_sn}</discont>
                                                </id>
                                            </object>
                                        </top>
                                    </filter>
                                </get>
                            </rpc>
                        </soapenv:Body>
                       </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload, timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object'):
                return resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']
            else:
                return response

    def ontpwe3prof(self, message_id='1', cms_user_nm='rootgod', network_nm='', ontpwe3prof_id='1', http_timeout=1):
        """
        Description
        -----------
        function ontpwe3prof() performs a http/xml query for the provided network_nm(e7_node) requesting the <OntPwe3Prof> object type specified by the ontpwe3prof_id provided

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param ontpwe3prof_id: identifies the ID of the profile that sets the ONT PWE3 mode. Use 1 (also the default, if not supplied) for the system-default profile, which is set to use either T1 or E1 mode in the management interface, as described in pg.141 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type ontpwe3prof_id:str

        :return: ontpwe3prof() will return a requests.models.Response object on a failed query, and a dict on a successful query
        """
        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <get-config>
                                    <source>
                                        <running/>
                                    </source>
                                    <filter type="subtree">
                                        <top>
                                            <object>
                                                <type>OntPwe3Prof</type>
                                                <id>
                                                    <ontpwe3prof>{ontpwe3prof_id}</ontpwe3prof>
                                                </id>
                                            </object>
                                        </top>
                                    </filter>
                                </get-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object'):
                return resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']
            else:
                return response

    def vlan(self, message_id='1', cms_user_nm='rootgod', network_nm='', vlan_id='1', http_timeout=1):
        """
        Description
        -----------
        function vlan() performs a http/xml query for the provided network_nm(e7_node) requesting the <Vlan> object type specified by the vlan_id provided

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param vlan_id: Identifies the VLAN: 2 to 4093, excluding any reserved VLANs, as described in pg.50 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type vlan_id:str

        :return: vlan() will return a requests.models.Response object on a failed query, and a dict on a successful query
        """
        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <get-config>
                                    <source>
                                        <running/>
                                    </source>
                                <filter type="subtree">
                                    <top>
                                        <object>
                                        <type>Vlan</type>
                                            <id>
                                                <vlan>{vlan_id}</vlan>
                                            </id>
                                        </object>
                                    </top>
                                </filter>
                                </get-config>
                            </rpc>
                        </soapenv:Body>
                       </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object'):
                return resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']
            else:
                return response

    def show_ont(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, action_args={' ': ''}, after_filter={' ': ''}):
        """
        Description
        -----------
        function show_ont() performs the CLI command show-ont for the provided network_nm(e7_node) through a http/xml query

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param action_args: similar to attr_filter param in other query functions, action_args acts as a filter for the query
        :type action_args:dict

        :param after_filter: this parameter is a dict of the child object to input in the <after> element as shown in pg.18 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type after_filter:dict

        :return: show_ont() returns a list of dicts on a successful call and a requests.models.Response object on a failed call.
        """
        if ' ' not in after_filter.keys():
            _after_filter = f"""<after>
                                    <type>Ont</type>
                                    <id>
                                        <ont>{after_filter['ont']}</ont>
                                    </id>
                                </after>"""
        else:
            _after_filter = """"""

        valid_action_args = ['admin', 'serno', 'reg-id', 'subscr-id', 'pon', 'ontprof', 'ont']
        if ' ' not in action_args.keys():
            _action_args = """"""
            for arg in action_args.items():
                if arg[0] in valid_action_args:
                    if arg[0] == 'pon':
                        _action_args = _action_args + f"""<linked-pon>
                                                          <type>GponPort</type>
                                                          <id>
                                                          <shelf>{arg[1]['shelf']}</shelf>
                                                          <card>{arg[1]['card']}</card>
                                                          <gponport>{arg[1]['gponport']}</gponport>
                                                          </id>
                                                          </linked-pon>"""
                    elif arg[0] == 'ontprof':
                        _action_args = _action_args + f"""<ontprof>
                                                          <type>OntProf</type>
                                                          <id>
                                                          <ontprof>{arg[1]}</ontprof>
                                                          </id>
                                                          </ontprof>"""
                    elif arg[0] == 'ont':
                        _action_args = _action_args + f"""<ont>
                                                          <type>Ont</type>
                                                          <id>
                                                          <ont>{arg[1]}</ont>
                                                          </id>
                                                          </ont>"""
                    else:
                        _action_args = _action_args + f"""<{arg[0]}>{arg[1]}</{arg[0]}>"""
        else:
            _action_args = """"""

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <action>
                                    <action-type>show-ont</action-type>
                                    <action-args>
                                    {_action_args}
                                    {_after_filter}
                                    </action-args>
                                </action>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.action-reply.more'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['action-reply']['match']
                _after_filter_ = resp_dict['get']['object']['id']
                try:
                    if isinstance(self.resp_show_ont, list):
                        self.resp_show_ont.append(resp_dict)
                except:
                    self.resp_show_ont = []
                    self.resp_show_ont.append(resp_dict)
                return self.show_ont(message_id=message_id, cms_user_nm=cms_user_nm, network_nm=network_nm, http_timeout=http_timeout, after_filter=_after_filter_, action_args=action_args)

            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.action-reply.match'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['action-reply']['match']
                try:
                    if isinstance(self.resp_show_ont, list):
                        self.resp_show_ont.append(resp_dict)
                        resp_show_ont = self.resp_show_ont
                        del self.resp_show_ont
                        return resp_show_ont
                except:
                    self.resp_show_ont = []
                    self.resp_show_ont.append(resp_dict)
                    resp_show_ont = self.resp_show_ont
                    del self.resp_show_ont
                    return resp_show_ont
            
            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.action-reply'):
                try:
                    if isinstance(self.resp_show_ont, list):
                        resp_show_ont = self.resp_show_ont
                        del self.resp_show_ont
                        return resp_show_ont
                except:
                    return response

            else:
                return response

    def show_dhcp_leases(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, action_args={' ': ''}, after_filter={' ': ''}):
        """
        Description
        -----------
        function show_dhcp_leases() performs the CLI command show-dhcp-leases for the provided network_nm(e7_node) through a http/xml query

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param action_args: similar to attr_filter param in other query functions, action_args acts as a filter for the query
        :type action_args:dict

        :param after_filter: this parameter is a dict of the child object to input in the <after> element as shown in pg.18 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type after_filter:dict

        :return: show_dhcp_leases() returns a list of dicts on a successful call and a requests.models.Response object on a failed call.
        """
        valid_action_args = ['vlan', 'ontethge', 'ontethfe', 'ethintf', 'gponport']
        if ' ' not in action_args.keys():
            _action_args = """"""
            for arg in action_args.items():
                if arg[0] in valid_action_args:
                    if 'vlan' in arg[0]:
                        _action_args += f"""<vlan>{arg[1]}</vlan>"""
                    elif 'ontethge' in arg[0]:
                        _action_args += f"""<object>
                                                <type>OntEthGe</type>
                                                <id>
                                                    <ont>{arg[1]['ont']}</ont>
                                                    <ontslot>3</ontslot>
                                                    <ontethge>{arg[1]['ontethge']}</ontethge>
                                                </id>
                                            </object>"""
                    elif 'ontethfe' in arg[0]:
                        _action_args += f"""<object>
                                                <type>OntEthFe</type>
                                                <id>
                                                    <ont>{arg[1]['ont']}</ont>
                                                    <ontslot>5</ontslot>
                                                    <ontethfe>{arg[1]['ontethfe']}</ontethfe>
                                                </id>
                                            </object>"""
                    elif 'gponport' in arg[0]:
                        _action_args += f"""<object>
                                                <type>GponPort</type>
                                                <id>
                                                    <shelf>{arg[1]['shelf']}</shelf>
                                                    <card>{arg[1]['card']}</card>
                                                    <gponport>{arg[1]['gponport']}</gponport>
                                                </id>
                                            </object>"""
                    elif 'ethintf' in arg[0]:
                        _action_args += f"""<object>
                                                <type>EthIntf</type>
                                                <id>
                                                    <shelf>{arg[1]['shelf']}</shelf>
                                                    <card>{arg[1]['card']}</card>
                                                    <ethintf>{arg[1]['ethintf']}</ethintf>
                                                </id>
                                            </object>"""
                    else:
                        pass
                else:
                    pass
        else:
            _action_args = """"""

        if ' ' not in after_filter.keys():
            _after_filter = f"""<after>{xmltodict.unparse(after_filter, full_document=False)}</after>"""
        else:
            _after_filter = """"""

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <action>
                                    <action-type>show-dhcp-leases</action-type>
                                    <action-args>
                                    {_action_args}
                                    {_after_filter}
                                    </action-args>
                                </action>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.action-reply.more'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['action-reply']['entry']
                _after_filter_ = resp_dict[len(resp_dict)-1]
                try:
                    if isinstance(self.resp_show_dhcp_leases, list):
                        self.resp_show_dhcp_leases.extend(resp_dict)
                except NameError:
                    self.resp_show_dhcp_leases = []
                    self.resp_show_dhcp_leases.extend(resp_dict)
                return self.show_dhcp_leases(message_id=message_id, cms_user_nm=cms_user_nm, network_nm=network_nm, http_timeout=http_timeout, action_args=action_args, after_filter=_after_filter_)
            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.action-reply.entry'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['action-reply']['entry']
                try:
                    if isinstance(self.resp_show_dhcp_leases, list):
                        if isinstance(resp_dict, list):
                            self.resp_show_dhcp_leases.extend(resp_dict)
                        else:
                            self.resp_show_dhcp_leases.append(resp_dict)
                except NameError:
                    self.resp_show_dhcp_leases = []
                    if isinstance(resp_dict, list):
                        self.resp_show_dhcp_leases.extend(resp_dict)
                    else:
                        self.resp_show_dhcp_leases.append(resp_dict)
                resp = self.resp_show_dhcp_leases
                del self.resp_show_dhcp_leases
                return resp
            else:
                return response

    def show_vlan_members(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, vlan_id='1', after_filter={' ': ''}):
        """
        Description
        -----------
        function show_vlan_members() performs the CLI command show-vlan-members for the provided network_nm(e7_node) through a http/xml query

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param vlan_id: the vlan id
        :type vlan_id:str

        :param after_filter: this parameter is a dict of the child object to input in the <after> element as shown in pg.18 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type after_filter:dict

        :return: show_vlan_members() returns a list of dicts on a successful call and a requests.models.Response object on a failed call.
        """
        if ' ' not in after_filter.keys():
            _after_filter = f"""<after>{xmltodict.unparse(after_filter, full_document=False)}</after>"""
        else:
            _after_filter = """"""
        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <action>
                                    <action-type>show-vlan-intforeaps</action-type>
                                    <action-args>
                                        <object>
                                            <type>Vlan</type>
                                            <id>
                                                <vlan>{vlan_id}</vlan>
                                            </id>
                                        </object>
                                        {_after_filter}
                                    </action-args>
                                </action>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.action-reply.more'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['action-reply']['match']
                __after_filter = resp_dict[len(resp_dict) - 1]
                try:
                    if isinstance(self.resp_show_vlan_members, list):
                        self.resp_show_vlan_members.extend(resp_dict)
                except:
                    self.resp_show_vlan_members = []
                    self.resp_show_vlan_members.extend(resp_dict)
                return self.show_vlan_members(message_id=message_id, cms_user_nm=cms_user_nm, network_nm=network_nm, http_timeout=http_timeout, vlan_id=vlan_id, after_filter=__after_filter)
            elif pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.action-reply.match'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['action-reply']['match']
                try:
                    if isinstance(self.resp_show_vlan_members, list):
                        if isinstance(resp_dict, list):
                            self.resp_show_vlan_members.extend(resp_dict)
                        else:
                            self.resp_show_vlan_members.append(resp_dict)
                except:
                    self.resp_show_vlan_members = []
                    if isinstance(resp_dict, list):
                        self.resp_show_vlan_members.extend(resp_dict)
                    else:
                        self.resp_show_vlan_members.append(resp_dict)
                resp = self.resp_show_vlan_members
                del self.resp_show_vlan_members
                return resp
            else:
                return response


class Create_E7_Data():

    def __init__(self, cms_nbi_connect_object):
        """
        Description
        -----------
        Class (Create_E7_Data) is the creation query constructor/posting class for the E7 CMS NETCONF NBI

        Attributes
        ----------
        :var self.cms_nbi_connect_object: accepts object created by the CMS_NBI_Client
        :type self.cms_nbi_connect_object: object
        """
        # Test if the provided object is of a CMS_NBI_Client instance

        if isinstance(cms_nbi_connect_object, CMS_NBI_Client):
            pass
        else:
            raise ValueError(
                f"""Query_E7_Data accepts a instance of CMS_NBI_Client, a instance of {type(cms_nbi_connect_object)}""")
        self.cms_nbi_connect_object = cms_nbi_connect_object
        # Test if the cms_netconf_url is a str object and contains the e7 uri
        if isinstance(self.cms_nbi_connect_object.cms_netconf_url, str):
            if self.cms_nbi_connect_object.cms_nbi_config['cms_netconf_uri']['e7'] in self.cms_nbi_connect_object.cms_netconf_url:
                pass
            else:
                raise ValueError(f"""uri:{self.cms_nbi_connect_object.cms_nbi_config['cms_netconf_uri']['e7']} was not found in self.cms_nbi_connect_object.cms_netconf_url:{self.cms_nbi_connect_object.cms_netconf_url}""")
        else:
            raise ValueError(f"""self.cms_nbi_connect_object.cms_netconf_url must be a str object""")
        # test if the session_id is a str object
        if isinstance(self.cms_nbi_connect_object.session_id, str):
            if self.cms_nbi_connect_object.session_id.isdigit():
                pass
            else:
                raise ValueError(f"""self.cms_nbi_connect_object.session_id must be a int in a str object""")
        else:
            raise ValueError(f"""self.cms_nbi_connect_object.session_id must be a str object""")

    def ont(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, ont_id='0', admin_state='enabled', ont_sn='0', reg_id='', sub_id='', ont_desc='', ontpwe3prof_id='1', ontprof_id=''):
        """
        Description
        -----------
        function ont() performs a http/xml creation query for the provided network_nm(e7_node) requesting an <Ont> object be created with the provided details

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param ont_id: Identifies the ONT by its E7 scope ID (1 to 64000000), submitting '0' requests the ont be built on the first available ID, as described in pg.129 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type ont_sn:str

        :param admin_state: operational status of the created ONT, valid values are [disabled,enabled,enabled-no-alarms], this is explained further in pg.237 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type admin_state:str

        :param ont_sn: identifies the Hexadecimal representation of the ONT serial number, to assign the SN at a later date, input '0', as described in pg.140 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type ont_sn:str

        :param reg_id:ONT registration ID that is the RONTA identifier., as described in pg.232 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type reg_id:str

        :param sub_id: Identifies the subscriber ID., as described in pg.63 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type sub_id:str

        :param ont_desc: Identifies the ONT Description
        :type ont_desc:str

        :param ontpwe3prof_id: identifies the ID of the profile that sets the ONT PWE3 mode. Use 1 (also the default, if not supplied) for the system-default profile, which is set to use either T1 or E1 mode in the management interface. as described in pg.141 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type ontpwe3prof_id:str

        :param ontprof_id: identifies the ID of a global or local ONT profile (1 to 50, or one of the default global profiles listed in Global ONT Profile IDs, as described in pg.282-285 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type ontprof_id:str

        :return: ont() returns a response.models.Response object on a failed call, and a nested dict on a successful call
        """

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <edit-config>
                                    <target>
                                        <running/>
                                    </target>
                                    <config>
                                        <top>
                                            <object operation="create" get-config="true">
                                                <type>Ont</type>
                                                <id>
                                                    <ont>{ont_id}</ont>
                                                </id>
                                                <admin>{admin_state}</admin>
                                                <serno>{ont_sn}</serno>
                                                <reg-id>{reg_id}</reg-id>
                                                <subscr-id>{sub_id}</subscr-id>
                                                <descr>{ont_desc}</descr>
                                                <pwe3prof>
                                                    <type>OntPwe3Prof</type>
                                                    <id>
                                                        <ontpwe3prof>{ontpwe3prof_id}</ontpwe3prof>
                                                    </id>
                                                </pwe3prof>
                                                <ontprof>
                                                    <type>OntProf</type>
                                                    <id>
                                                        <ontprof>{ontprof_id}</ontprof>
                                                    </id>
                                                </ontprof>
                                            </object>
                                        </top>
                                    </config>
                                </edit-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload, timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object'):
                return resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']
            else:
                return response

    def vlan(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, vlan_id='', name='', igmp_mode='flood', vlanigmpprof_id='1', dhcp_mode='none', mac_force_forw='false', ip_src_verify='false', mac_learn='true', ae_ont_discovery='false', pon_tlan='false', pon_hairpin='false', igmp_pbit='pbit-4', dhcp_svc_profile={'dhcp-svc-prof': ''}, option82_enable='true', eth_opt82prof_id='2', gpon_opt82prof_id='1', mobility='false', pppoe_profile={'pppoe-prof': ''}):
        """
        Description
        -----------
        function vlan() performs a http/xml creation query for the provided network_nm(e7_node) requesting an <Vlan> object be created with the provided details

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param vlan_id: Identifies the VLAN: 2 to 4093 (Except for 1002-1005 which are reserved for E7 operation.), excluding any reserved VLANs as described in pg.50 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type vlan_id:str

        :param name:Identifies the name of the VLAN. Spaces and special characters are permitted. as described in pg.43 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type name:str

        :param igmp_mode: Identifies the igmp_mode used by the e7 node to treat mcast traffic on the vlan, as described in pg.43 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type igmp_mode:str

        :param vlanigmpprof_id: Numerical identifier for the local profile (1 to 20), The local IGMP profile ID can be viewed in the management interface. In the IGMP profile list, double-click a profile to view its ID above the Name field.  If <igmp-prof> is not specified, the systemdefault IGMP profile (1) is used.  this is described in pg.43 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type vlanigmpprof_id:str

        :param dhcp_mode: this setting enables or disabled dhcp snooping on the vlan, as described in pg.43 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type dhcp_mode:str

        :param mac_force_forw:this setting enables or disabled mac_force_forwarding on the vlan, as described in pg.43 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type mac_force_forw:str

        :param ip_src_verify: enable or disables IP source verification (binding the IP and MAC addresses to the physical ONT Ethernet port), as described in pg.43 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type ip_src_verify:str

        :param mac_learn: enables or disables mac-learning on the vlan, "Only applicable for E7-20 and E7-2 standalone systems; Modular Chassis configurations only support MAC learning", as described in pg.43 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type mac_learn:str

        :param ae_ont_discovery: enables or disables ae-ont-discovery, (Only supported when DHCP snooping is enabled, as described in pg.43 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type ae_ont_discovery:str

        :param pon_tlan: enables or disables pon-tlan perameter, as described in pg.43 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type pon_tlan:str

        :param pon_hairpin:(Applicable for TLAN and T1/E3 PWE3 services) this allows for traffice to be hair-pin back to the same olt on a differing or same uni, this is explained better in pg.337 of Calix E-Series (E7 OS R2.5) Engineering and Planning Guide
        :type pon_hairpin:str

        :param igmp_pbit: The P-bit value(pbit-0 through pbit-7) for IGMP traffic that passes through the system, allowing the traffic type to be treated differently as it passes through the network. this is explained better in pg.337 of Calix E-Series (E7 OS R2.5) Engineering and Planning Guide
        :type igmp_pbit:str

        :param dhcp_svc_profile:Required for the configuration of DHCPv4 Proxy (Layer 3 DHCP Relay) on the client-side VLAN,The selected profile determines the DHCP Proxy Agent IP interface and IP address of the DHCP server(s). this is explained better in pg.337 of Calix E-Series (E7 OS R2.5) Engineering and Planning Guide
        :type dhcp_svc_profile:dict

        :param option82_enable:Enables or disables Option 82/LDRA at the VLAN level
        :type option82_enable:str

        :param eth_opt82prof_id:Access Identifier Profile for Ethernet/xDSL subscribers, specifying the Circuit and Remote ID format for Option 82 content insertion, this is explained better in pg.337 of Calix E-Series (E7 OS R2.5) Engineering and Planning Guide
        :type eth_opt82prof_id:str

        :param gpon_opt82prof_id:Access Identifier Profile for GPON subscribers, specifying the Circuit and Remote ID format for Option 82 content insertion, this is explained better in pg.337 of Calix E-Series (E7 OS R2.5) Engineering and Planning Guide
        :type gpon_opt82prof_id:str

        :param mobility:Enables or disables the ability for client devices to move freely between different ONTs on the same PON or card. (Not supported across multiple cards, this is explained better in pg.338 of Calix E-Series (E7 OS R2.5) Engineering and Planning Guide
        :type mobility:str

        :param pppoe_profile:Assign a previously-created PPPoE profile. When a PPPoE profile is selected, the DHCP features are disabled. Setting a VLAN PPPoE profile to “none” passes through all PPPoE traffic, transparently. If a PPPoE profile is used with PPPoE snoop, a list of all the active sessions and statistics are available, and the PPPoE stack is enabled, which passes through PPPoE traffic transparently as long as the Clients/BRAS are operating normally (illegal packets will be dropped),this is explained better in pg.338 of Calix E-Series (E7 OS R2.5) Engineering and Planning Guide
        :type pppoe_profile:dict

        :return: vlan() function will return a dict on a successfull call, and a request.Models.Response object on a failed call
        """
        if isinstance(pppoe_profile['pppoe-prof'], dict):
            _pppoe_profile = xmltodict.unparse(pppoe_profile, full_document=False)
        else:
            _pppoe_profile = """<pppoe-prof></pppoe-prof>"""

        if isinstance(dhcp_svc_profile['dhcp-svc-prof'], dict):
            _dhcp_svc_prof_id = xmltodict.unparse(dhcp_svc_profile, full_document=False)
        else:
            _dhcp_svc_prof_id = """<dhcp-svc-prof></dhcp-svc-prof>"""

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <edit-config>
                                    <target>
                                        <running/>
                                    </target>
                                    <config>
                                        <top>
                                            <object operation="create" get-config="true">
                                                <type>Vlan</type>
                                                <id>
                                                    <vlan>{vlan_id}</vlan>
                                                </id>
                                                <name>{name}</name>
                                                <igmp-mode>{igmp_mode}</igmp-mode>
                                                <igmp-prof>
                                                    <type>VlanIgmpProf</type>
                                                    <id>
                                                        <vlanigmpprof>{vlanigmpprof_id}</vlanigmpprof>
                                                    </id>
                                                </igmp-prof>
                                                <dhcp-mode>{dhcp_mode}</dhcp-mode>
                                                <mac-force-forw>{mac_force_forw}</mac-force-forw>
                                                <ip-src-verify>{ip_src_verify}</ip-src-verify>
                                                <mac-learn>{mac_learn}</mac-learn>
                                                <ae-ont-discovery>{ae_ont_discovery}</ae-ont-discovery>
                                                <pon-tlan>{pon_tlan}</pon-tlan>
                                                <pon-hairpin>{pon_hairpin}</pon-hairpin>
                                                <igmp-pbit>{igmp_pbit}</igmp-pbit>
                                                {_dhcp_svc_prof_id}
                                                <option82-enable>{option82_enable}</option82-enable>
                                                <eth-opt82prof>
                                                    <type>Opt82Prof</type>
                                                    <id>
                                                        <opt82prof>{eth_opt82prof_id}</opt82prof>
                                                    </id>
                                                </eth-opt82prof>
                                                <gpon-opt82prof>
                                                    <type>Opt82Prof</type>
                                                    <id>
                                                        <opt82prof>{gpon_opt82prof_id}</opt82prof>
                                                    </id>
                                                </gpon-opt82prof>
                                                <mobility>{mobility}</mobility>
                                                {_pppoe_profile}
                                            </object>
                                        </top>
                                    </config>
                                </edit-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload, timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object'):
                return resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']
            else:
                return response

    def vlan_members(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, vlan_id='', vlan_member_id='0', int_id={' ':''}):
        """
        Description
        -----------
        function vlan_members() performs a http/xml creation query for the provided network_nm(e7_node) requesting an <VlanMem> object be created with the provided details

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param vlan_id:  Identifies the VLAN: 2 to 4093 (Except for 1002-1005 which are reserved for E7 operation.), excluding any reserved VLANs as described in pg.50 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type vlan_id:str

        :param vlan_member_id: —Identifies the VLAN member. Use one of the following: 0—The E7 auto-generates the VLAN member ID. 1 to 1000—Supply the VLAN member ID to use (must be unique). as described in pg.50 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type vlan_member_id:str

        :param int_id: identifies the interface object being added to the vlan object, please review pg.50 of Calix Management System (CMS) R15.x Northbound Interface API Guide for more information
        :type int_id:dict

        :return: vlan_members() will return a dict on a successfull query and a response.models.response object on a failed query

        Example
        -----------
        IMPORTANT NOTE

        You will need to submit the correct structured dictionary to the int_id param

        ------FOR ETHERNET INTERFACES------
        {
            'ethintf': {
                    'type': 'EthIntf',
                     'id': {
                         'shelf': '1',
                         'card': '1',
                         'ethintf': '1'}
                     }
         }
        Create_E7_Data.vlan_members(message_id='1',
                                    cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                    network_nm='NTWK-Example_Name',
                                    vlan_member_id='0',
                                    int_id={'ethintf': {
                                                'type': 'EthIntf',
                                                 'id': {
                                                     'shelf': '1',
                                                     'card': '1',
                                                     'ethintf': '1'}
                                                 }
                                            })

        ------FOR ERPS/G8032 RINGS------
        {
            'eapsintf': {
                'type': 'EapsIntf',
                'id': {'eapsintf':'1'
                      }
            }
        }
        Create_E7_Data.vlan_members(message_id='1',
                                    cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                    network_nm='NTWK-Example_Name',
                                    vlan_member_id='0',
                                    int_id={'eapsintf': {
                                                'type': 'EapsIntf',
                                                'id': {'eapsintf':'1'}
                                                        }
                                            })

        ------FOR LAG INTERFACES------
        {
            'lagintf': {
                    'type': 'LagIntf',
                     'id': {
                         'lagintf': '1'
                        }
                     }
        }
        Create_E7_Data.vlan_members(message_id='1',
                                    cms_user_nm=client.cms_nbi_config['cms_nodes']['example_node']['cms_creds']['user_nm'],
                                    network_nm='NTWK-Example_Name',
                                    vlan_member_id='0',
                                    int_id={'lagintf': {
                                                        'type': 'LagIntf',
                                                         'id': {'lagintf': '1'}
                                                         }
                                            })
        """

        if ' ' not in int_id.keys() and len(int_id.keys()) == 1:
            if 'ethintf' in int_id.keys():
                _int_id = xmltodict.unparse(int_id['ethintf'], full_document=False)
            elif 'lagintf' in int_id.keys():
                _int_id = xmltodict.unparse(int_id['lagintf'], full_document=False)
            elif 'eapsintf' in int_id.keys():
                _int_id = xmltodict.unparse(int_id['eapsintf'], full_document=False)
            else:
                raise AttributeError("int_id expects a object to add to the vlan_members please review and resubmit")
        else:
            raise AttributeError("int_id expects a object to add to the vlan_members please review and resubmit")

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <edit-config>
                                    <target>
                                        <running/>
                                    </target>
                                    <config>
                                        <top>
                                            <object operation="create" get-config="true">
                                                <type>VlanMem</type>
                                                <id>
                                                    <vlan>{vlan_id}</vlan>
                                                    <vlanmem>{vlan_member_id}</vlanmem>
                                                </id>
                                                <member>
                                                    {_int_id}
                                                </member>
                                            </object>
                                        </top>
                                    </config>
                                </edit-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.data.top.object'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']['data']['top']['object']
                return resp_dict
            else:
                return response


class Update_E7_Data():

    def __init__(self, cms_nbi_connect_object):
        """
                Description
                -----------
                Class (Update_E7_Data) is the update/merge query constructor/posting class for the E7 CMS NETCONF NBI

                Attributes
                ----------
                :var self.cms_nbi_connect_object: accepts object created by the CMS_NBI_Client
                :type self.cms_nbi_connect_object: object
                """
        # Test if the provided object is of a CMS_NBI_Client instance

        if isinstance(cms_nbi_connect_object, CMS_NBI_Client):
            pass
        else:
            raise ValueError(
                f"""Query_E7_Data accepts a instance of CMS_NBI_Client, a instance of {type(cms_nbi_connect_object)}""")
        self.cms_nbi_connect_object = cms_nbi_connect_object
        # Test if the cms_netconf_url is a str object and contains the e7 uri
        if isinstance(self.cms_nbi_connect_object.cms_netconf_url, str):
            if self.cms_nbi_connect_object.cms_nbi_config['cms_netconf_uri']['e7'] in self.cms_nbi_connect_object.cms_netconf_url:
                pass
            else:
                raise ValueError(
                    f"""uri:{self.cms_nbi_connect_object.cms_nbi_config['cms_netconf_uri']['e7']} was not found in self.cms_nbi_connect_object.cms_netconf_url:{self.cms_nbi_connect_object.cms_netconf_url}""")
        else:
            raise ValueError(f"""self.cms_nbi_connect_object.cms_netconf_url must be a str object""")
        # test if the session_id is a str object
        if isinstance(self.cms_nbi_connect_object.session_id, str):
            if self.cms_nbi_connect_object.session_id.isdigit():
                pass
            else:
                raise ValueError(f"""self.cms_nbi_connect_object.session_id must be a int in a str object""")
        else:
            raise ValueError(f"""self.cms_nbi_connect_object.session_id must be a str object""")


class Delete_E7_Data():

    def __init__(self, cms_nbi_connect_object):
        """
                Description
                -----------
                Class (Delete_E7_Data) is the delete query constructor/posting class for the E7 CMS NETCONF NBI

                Attributes
                ----------
                :var self.cms_nbi_connect_object: accepts object created by the CMS_NBI_Client
                :type self.cms_nbi_connect_object: object
                """
        # Test if the provided object is of a CMS_NBI_Client instance

        if isinstance(cms_nbi_connect_object, CMS_NBI_Client):
            pass
        else:
            raise ValueError(
                f"""Query_E7_Data accepts a instance of CMS_NBI_Client, a instance of {type(cms_nbi_connect_object)}""")
        self.cms_nbi_connect_object = cms_nbi_connect_object
        # Test if the cms_netconf_url is a str object and contains the e7 uri
        if isinstance(self.cms_nbi_connect_object.cms_netconf_url, str):
            if self.cms_nbi_connect_object.cms_nbi_config['cms_netconf_uri']['e7'] in self.cms_nbi_connect_object.cms_netconf_url:
                pass
            else:
                raise ValueError(
                    f"""uri:{self.cms_nbi_connect_object.cms_nbi_config['cms_netconf_uri']['e7']} was not found in self.cms_nbi_connect_object.cms_netconf_url:{self.cms_nbi_connect_object.cms_netconf_url}""")
        else:
            raise ValueError(f"""self.cms_nbi_connect_object.cms_netconf_url must be a str object""")
        # test if the session_id is a str object
        if isinstance(self.cms_nbi_connect_object.session_id, str):
            if self.cms_nbi_connect_object.session_id.isdigit():
                pass
            else:
                raise ValueError(f"""self.cms_nbi_connect_object.session_id must be a int in a str object""")
        else:
            raise ValueError(f"""self.cms_nbi_connect_object.session_id must be a str object""")

    def ont(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, ont_id='', force='false'):
        """
        Description
        -----------
        function ont() performs a http/xml creation query for the provided network_nm(e7_node) requesting an <Ont> object be deleted with the provided details

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param ont_id: Identifies the ONT by its E7 scope ID (1 to 64000000), as described in pg.129 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type ont_id:str

        :param force: force expects a boolean string ['true', 'false'] Note: For a non-force(ie..force='false') delete to be successful, all service must be removed from the ONT. force="true"—Perform a force delete (deletes that all services on the ONT). as described in pg.47 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type force:str

        :raise:
            AttributeError: will be raised if the ont_id is not a digit in the form of a str object

        :return: ont() returns a response.models.Response object on a failed call, and a nested dict on a successful call
        """
        if isinstance(ont_id, str):
            if ont_id.isdigit():
                pass
            else:
                raise AttributeError("""param:ont_id is expected to be a digit in the form of a str object""")
        else:
            raise AttributeError("""param:ont_id is expected to be a digit in the form of a str object""")

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <edit-config>
                                    <target>
                                        <running/>
                                    </target>
                                    <config>
                                        <top>
                                            <object operation="delete" force="{force}">
                                                <type>Ont</type>
                                                <id>
                                                    <ont>{ont_id}</ont>
                                                </id>
                                            </object>
                                        </top>
                                    </config>
                                </edit-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.ok'):
                return resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']
            else:
                return response

    def vlan(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, vlan_id='', force='false'):
        """
        Description
        -----------
        function vlan() performs a http/xml Deletion query for the provided network_nm(e7_node) requesting an <Vlan> object be deleted with the provided details

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param vlan_id: Identifies the VLAN: 2 to 4093 (Except for 1002-1005 which are reserved for E7 operation.), excluding any reserved VLANs as described in pg.50 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type vlan_id:str

        :param force: force expects a boolean string ['true', 'false'] Note: For a non-force(ie..force='false') delete to be successful, all membership must be removed from the vlan. force="true"—Perform a force delete (deletes that all memberships on the VLAN). as described in pg.47 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type force:str

        :raise:
            AttributeError: will be raised if the vlan_id is not a digit in the form of a str object

        :return: ont() returns a response.models.Response object on a failed call, and a nested dict on a successful call
        """
        if isinstance(vlan_id, str):
            if vlan_id.isdigit():
                pass
            else:
                raise AttributeError("""param:vlan_id is expected to be a digit in the form of a str object""")
        else:
            raise AttributeError("""param:vlan_id is expected to be a digit in the form of a str object""")

        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                                <soapenv:Body>
                                    <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                        <edit-config>
                                            <target>
                                                <running/>
                                            </target>
                                            <config>
                                                <top>
                                                    <object operation="delete" force="{force}">
                                                        <type>Vlan</type>
                                                        <id>
                                                            <vlan>{vlan_id}</vlan>
                                                        </id>
                                                    </object>
                                                </top>
                                            </config>
                                        </edit-config>
                                    </rpc>
                                </soapenv:Body>
                            </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.ok'):
                return resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']
            else:
                return response

    def vlanmem(self, message_id='1', cms_user_nm='rootgod', network_nm='', http_timeout=1, vlan_id='', vlan_member_id='', force='false'):
        """
        Description
        -----------
        function vlan_members() performs a http/xml creation query for the provided network_nm(e7_node) requesting an <VlanMem> object be created with the provided details

        Attributes
        ----------
        :param message_id: is the message_id used by the cms server to correlate http responses, if None is provided and self.cms_nbi_connect_object.message_id is None the default of 1 will be used
        :type message_id:str

        :param cms_user_nm: this parameter contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param network_nm: this parameter contains the node name, which is made of the case-sensitive name of the E7 OS platform, preceded by NTWK-. Example: NTWK-Pet02E7. The nodename value can consist of alphanumeric, underscore, and space characters, this is described in pg.26 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type network_nm:str

        :param http_timeout: this parameter is fed to the request.request() function as a timeout more can be read at the request library docs
        :type http_timeout:int

        :param vlan_id:  Identifies the VLAN: 2 to 4093 (Except for 1002-1005 which are reserved for E7 operation.), excluding any reserved VLANs as described in pg.50 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type vlan_id:str

        :param vlan_member_id: —Identifies the VLAN member. 1 to 1000 as described in pg.50 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type vlan_member_id:str

        :return: vlan_members() will return a dict on a successfull query and a response.models.response object on a failed query

        Example
        -----------

        """
        payload = f"""<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                            <rpc message-id="{message_id}" nodename="{network_nm}" username="{cms_user_nm}" sessionid="{self.cms_nbi_connect_object.session_id}">
                                <edit-config>
                                    <target>
                                        <running/>
                                    </target>
                                    <config>
                                        <top>
                                            <object operation="delete" force="{force}">
                                                <type>VlanMem</type>
                                                <id>
                                                    <vlan>{vlan_id}</vlan>
                                                    <vlanmem>{vlan_member_id}</vlanmem>
                                                </id>
                                            </object>
                                        </top>
                                    </config>
                                </edit-config>
                            </rpc>
                        </soapenv:Body>
                    </soapenv:Envelope>"""

        headers = {'Content-Type': 'text/xml;charset=ISO-8859-1',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        if 'https' not in self.cms_nbi_connect_object.cms_netconf_url:
            try:
                response = requests.post(url=self.cms_nbi_connect_object.cms_netconf_url, headers=headers, data=payload,
                                         timeout=http_timeout)
            except requests.exceptions.Timeout as e:
                # debating between exit and raise will update in future
                exit(f"{e}")
        else:
            # will need to research how to implement https connection with request library
            pass

        if response.status_code != 200:
            # if the response code is not 200 FALSE and the request.response object is returned.
            return response

        else:
            resp_dict = xmltodict.parse(response.content)
            if pydash.objects.has(resp_dict, 'soapenv:Envelope.soapenv:Body.rpc-reply.ok'):
                resp_dict = resp_dict['soapenv:Envelope']['soapenv:Body']['rpc-reply']
                return resp_dict
            else:
                return response


class Query_Rest_Data():

    def __init__(self, cms_nbi_connect_object):
        """
        Description
        -----------
        Class (Query_Rest_Data) is the REST query constructor/posting class for the CMS REST NBI

        Attributes
        ----------
        :var self.cms_nbi_connect_object: accepts object created by the CMS_NBI_Client
        :type self.cms_nbi_connect_object: object
        """
        # Test if the provided object is of a CMS_NBI_Client instance

        if isinstance(cms_nbi_connect_object, CMS_NBI_Client):
            pass
        else:
            raise ValueError(f"""Query_E7_Data accepts a instance of CMS_NBI_Client, a instance of {type(cms_nbi_connect_object)}""")
        self.cms_nbi_connect_object = cms_nbi_connect_object

    def device(self, protocol='http', port='8080', cms_user_nm='rootgod', cms_user_pass='root', cms_node_ip='localhost', device_type='', http_timeout=1):
        """
        Description
        -----------
        function device() performs a HTTP GET utilizing the request library to query the CMS REST NBI for the specified devices, as explained in pg.378 of Calix Management System (CMS) R15.x Northbound Interface API Guide

        Parameter(s)
        ------------
        :param protocol: this var determines the protocol to use when building the CMS REST NBI URL, CMS supports http/s as described in pg.14 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type protocol:str

        :param port: this var determines the TCP/UDP port to use when building the CMS REST NBI URL, this will be dependent on whether HTTP or HTTPS was chosen, this is described in pg.14 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type port:str

        :param cms_user_nm: this var contains the username for the CMS USER ACCOUNT utilized in the interactions, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_nm:str

        :param cms_user_pass: this var contains the plain text password for the provided username, this is described in pg.15 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type cms_user_pass:str

        :param cms_node_ip: this var contains the FQDN/IP of the targeted CMS node
        :type cms_node_ip:str

        :param device_type: device type is a str identifying the targeted device type, this is explained further in pg.378 of Calix Management System (CMS) R15.x Northbound Interface API Guide
        :type device_type:str

        :param http_timeout: this var contains the http_timeout for the request library, this is in the form of an int
        :type http_timeout:int

        :return: device() returns a list of nested dicts on a successful query and a request.models.Requests object on failed queries
        """
        cms_rest_url = f"""{protocol}://{cms_node_ip}:{port}{self.cms_nbi_connect_object.cms_nbi_config['cms_rest_uri']['devices']}{device_type}&limit=9999"""

        payload = ""

        headers = {'Content-Type': 'application/json',
                   'User-Agent': f'CMS_NBI_CONNECT-{cms_user_nm}'}

        try:
            response = requests.get(url=cms_rest_url, headers=headers, data=payload, auth=(cms_user_nm, cms_user_pass), timeout=http_timeout)
        except requests.exceptions.Timeout as e:
            # debating between exit and raise will update in future
            exit(f"{e}")

        if response.status_code == 200:
            return response.json()['data']
        else:
            return response
