execute

        High-level api: Supported operations are get, get_config, get_schema,
        dispatch, edit_config, copy_config, validate, commit, discard_changes,
        delete_config, lock, unlock, close_session, kill_session,
        poweroff_machine and reboot_machine. Since ModelDevice is a subclass of
        manager in ncclient package, any method supported by ncclient is
        available here. Refer to ncclient document for more details.

def execute(self, operation, *args, **kwargs):
        '''execute

        High-level api: Supported operations are get, get_config, get_schema,
        dispatch, edit_config, copy_config, validate, commit, discard_changes,
        delete_config, lock, unlock, close_session, kill_session,
        poweroff_machine and reboot_machine. Since ModelDevice is a subclass of
        manager in ncclient package, any method supported by ncclient is
        available here. Refer to ncclient document for more details.
        '''

        def pop_models():
            models = kwargs.pop('models', None)
            if models is None:
                return None
            else:
                if isinstance(models, str):
                    return [models]
                else:
                    return models

        def check_models(models):
            missing_models = set(models) - set(self.models_loaded)
            if missing_models:
                raise ModelMissing('please load model {} by calling ' \
                                   'method load_model() of device {}' \
                                   .format(str(list(missing_models))[1:-1],
                                           self))

        def build_filter(models, roots):
            if 'filter' in kwargs:
                logger.warning("argument 'filter' is ignored as argument "
                               "'models' is specified")
            if isinstance(models, str):
                models = [models]
            check_models(models)
            filter_ele = etree.Element(filter_tag, type='subtree')
            for root in roots:
                etree.SubElement(filter_ele, root)
            filter_xml = etree.tostring(filter_ele,
                                        encoding='unicode',
                                        pretty_print=False)
            logger.debug("argument 'filter' is set to '{}'".format(filter_xml))
            return filter_ele

        def get_access_type(model_name, root):
            check_models([model_name])
            node = list(self.models[model_name].tree.iterchildren(tag=root))[0]
            return node.get('access')

        # allow for operation string type
        if type(operation) is str:
            try:
                cls = manager.OPERATIONS[operation]
            except KeyError:
                supported_operations = list(manager.OPERATIONS.keys())
                raise ValueError("supported operations are {}, but not '{}'" \
                                 .format(str(supported_operations)[1:-1],
                                         operation))
        else:
            cls = operation
        if cls == operations.retrieve.Get:
            models = pop_models()
            if models is not None:
                check_models(models)
                roots = [k for k, v in self.roots.items()
                         if v in models and
                            (get_access_type(v, k) == 'read-write' or
                             get_access_type(v, k) == 'read-only')]
                if not roots:
                    raise ValueError('no readable roots found in your ' \
                                     'models: {}'.format(str(models)[1:-1]))
                kwargs['filter'] = build_filter(models, roots)
        elif cls == operations.retrieve.GetConfig:
            if not args and 'source' not in kwargs:
                args = tuple(['running'])
            models = pop_models()
            if models is not None:
                check_models(models)
                roots = [k for k, v in self.roots.items()
                         if v in models and
                            get_access_type(v, k) == 'read-write']
                if not roots:
                    raise ValueError('no writable roots found in your ' \
                                     'models: {}'.format(str(models)[1:-1]))
                kwargs['filter'] = build_filter(models, roots)
        elif cls == operations.edit.EditConfig:
            if args and isinstance(args[0], Config):
                args_list = list(args)
                args_list[0] = args[0].ele
                args = tuple(args_list)
            if 'target' not in kwargs and \
               'urn:ietf:params:netconf:capability:candidate:1.0' not in \
               self.server_capabilities and \
               'urn:ietf:params:netconf:capability:writable-running:1.0' in \
               self.server_capabilities:
                kwargs['target'] = 'running'
        reply = super().execute(cls, *args, **kwargs)
        if isinstance(reply, operations.rpc.RPCReply):
            reply.ns = self._get_ns(reply._root)
        if getattr(transport, 'notify', None) and \
           isinstance(reply, transport.notify.Notification):
            reply.ns = self._get_ns(reply._root_ele)
        return reply