def node_sub(self, node_self, node_other):
paths_delete = []<EOL>updates_replace = []<EOL>updates_update = []<EOL>done_list = []<EOL>def generate_delete(node, instance=True):<EOL><INDENT>paths_delete.append(gNMIComposer(self.device, node).get_path(instance=instance))<EOL><DEDENT>def generate_replace(node, instance=True):<EOL><INDENT>n = gNMIComposer(self.device, node)<EOL>json_value = n.get_json(instance=instance).encode()<EOL>value = TypedValue(json_val=json_value)<EOL>path = n.get_path(instance=instance)<EOL>updates_replace.append(Update(path=path, val=value))<EOL><DEDENT>def generate_update(node, instance=True):<EOL><INDENT>n = gNMIComposer(self.device, node)<EOL>json_value = n.get_json(instance=instance).encode()<EOL>value = TypedValue(json_val=json_value)<EOL>path = n.get_path(instance=instance)<EOL>updates_update.append(Update(path=path, val=value))<EOL><DEDENT>def leaf_list_seq_is_different(tag):<EOL><INDENT>if [i.text for i in node_self.iterchildren(tag=tag)] ==[i.text for i in node_other.iterchildren(tag=tag)]:<EOL><INDENT>return False<EOL><DEDENT>else:<EOL><INDENT>return True<EOL><DEDENT><DEDENT>def leaf_list_set_is_different(tag):<EOL><INDENT>s_list = [i.text for i in node_self.iterchildren(tag=tag)]<EOL>o_list = [i.text for i in node_other.iterchildren(tag=tag)]<EOL>if set(s_list) == set(o_list):<EOL><INDENT>return False<EOL><DEDENT>else:<EOL><INDENT>return True<EOL><DEDENT><DEDENT>def list_is_empty(tag):<EOL><INDENT>if [i for i in node_self.iterchildren(tag=tag)]:<EOL><INDENT>return False<EOL><DEDENT>else:<EOL><INDENT>return True<EOL><DEDENT><DEDENT>def list_seq_is_different(tag):<EOL><INDENT>s_list = [i for i in node_self.iterchildren(tag=tag)]<EOL>o_list = [i for i in node_other.iterchildren(tag=tag)]<EOL>if [self.device.get_xpath(n) for n in s_list] ==[self.device.get_xpath(n) for n in o_list]:<EOL><INDENT>return False<EOL><DEDENT>else:<EOL><INDENT>return True<EOL><DEDENT><DEDENT>def list_seq_is_inclusive(tag):<EOL><INDENT>s_list = [i for i in node_self.iterchildren(tag=tag)]<EOL>o_list = [i for i in node_other.iterchildren(tag=tag)]<EOL>s_seq = [self.device.get_xpath(n) for n in s_list]<EOL>o_seq = [self.device.get_xpath(n) for n in o_list]<EOL>if set(s_seq) <= set(o_seq) and[i for i in s_seq if i in o_seq] == o_seq:<EOL><INDENT>return True<EOL><DEDENT>else:<EOL><INDENT>return False<EOL><DEDENT><DEDENT>in_s_not_in_o, in_o_not_in_s, in_s_and_in_o =self._group_kids(node_self, node_other)<EOL>for child_s in in_s_not_in_o:<EOL><INDENT>schema_node = self.device.get_schema_node(child_s)<EOL>if schema_node.get('<STR_LIT:type>') == '<STR_LIT>':<EOL><INDENT>generate_update(child_s)<EOL><DEDENT>elif schema_node.get('<STR_LIT:type>') == '<STR_LIT>':<EOL><INDENT>if child_s.tag not in done_list:<EOL><INDENT>generate_replace(child_s, instance=False)<EOL>done_list.append(child_s.tag)<EOL><DEDENT><DEDENT>elif schema_node.get('<STR_LIT:type>') == '<STR_LIT>':<EOL><INDENT>generate_update(child_s)<EOL><DEDENT>elif schema_node.get('<STR_LIT:type>') == '<STR_LIT:list>':<EOL><INDENT>if schema_node.get('<STR_LIT>') == '<STR_LIT:user>':<EOL><INDENT>if child_s.tag not in done_list:<EOL><INDENT>generate_replace(child_s, instance=False)<EOL>done_list.append(child_s.tag)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>generate_update(child_s, instance=True)<EOL><DEDENT><DEDENT><DEDENT>for child_o in in_o_not_in_s:<EOL><INDENT>schema_node = self.device.get_schema_node(child_o)<EOL>if schema_node.get('<STR_LIT:type>') == '<STR_LIT>':<EOL><INDENT>generate_delete(child_o)<EOL><DEDENT>elif schema_node.get('<STR_LIT:type>') == '<STR_LIT>':<EOL><INDENT>if child_o.tag not in done_list:<EOL><INDENT>child_s = node_self.find(child_o.tag)<EOL>if child_s is None:<EOL><INDENT>generate_delete(child_o, instance=False)<EOL><DEDENT>else:<EOL><INDENT>generate_replace(child_s, instance=False)<EOL><DEDENT>done_list.append(child_o.tag)<EOL><DEDENT><DEDENT>elif schema_node.get('<STR_LIT:type>') == '<STR_LIT>':<EOL><INDENT>generate_delete(child_o)<EOL><DEDENT>elif schema_node.get('<STR_LIT:type>') == '<STR_LIT:list>':<EOL><INDENT>if schema_node.get('<STR_LIT>') == '<STR_LIT:user>':<EOL><INDENT>if list_seq_is_inclusive(child_o.tag):<EOL><INDENT>generate_delete(child_o, instance=True)<EOL><DEDENT>else:<EOL><INDENT>if child_o.tag not in done_list:<EOL><INDENT>generate_replace(child_o, instance=False)<EOL>done_list.append(child_o.tag)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>if list_is_empty(child_o.tag):<EOL><INDENT>if child_o.tag not in done_list:<EOL><INDENT>generate_delete(child_o, instance=False)<EOL>done_list.append(child_o.tag)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>generate_delete(child_o, instance=True)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>for child_s, child_o in in_s_and_in_o:<EOL><INDENT>schema_node = self.device.get_schema_node(child_s)<EOL>if schema_node.get('<STR_LIT:type>') == '<STR_LIT>':<EOL><INDENT>if child_s.text != child_o.text:<EOL><INDENT>generate_update(child_s)<EOL><DEDENT><DEDENT>elif schema_node.get('<STR_LIT:type>') == '<STR_LIT>':<EOL><INDENT>if child_s.tag not in done_list:<EOL><INDENT>if schema_node.get('<STR_LIT>') == '<STR_LIT:user>':<EOL><INDENT>if leaf_list_seq_is_different(child_s.tag):<EOL><INDENT>generate_replace(child_s, instance=False)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if leaf_list_set_is_different(child_s.tag):<EOL><INDENT>generate_replace(child_s, instance=False)<EOL><DEDENT><DEDENT>done_list.append(child_s.tag)<EOL><DEDENT><DEDENT>elif schema_node.get('<STR_LIT:type>') == '<STR_LIT>':<EOL><INDENT>if BaseCalculator(self.device, child_s, child_o).ne:<EOL><INDENT>d, r, u = self.node_sub(child_s, child_o)<EOL>paths_delete += d<EOL>updates_replace += r<EOL>updates_update += u<EOL><DEDENT><DEDENT>elif schema_node.get('<STR_LIT:type>') == '<STR_LIT:list>':<EOL><INDENT>if schema_node.get('<STR_LIT>') == '<STR_LIT:user>':<EOL><INDENT>if list_seq_is_different(child_s.tag):<EOL><INDENT>if child_s.tag not in done_list:<EOL><INDENT>generate_replace(child_s, instance=False)<EOL>done_list.append(child_s.tag)<EOL><DEDENT>else:<EOL><INDENT>if BaseCalculator(self.device, child_s, child_o).ne:<EOL><INDENT>d, r, u = self.node_sub(child_s, child_o)<EOL>paths_delete += d<EOL>updates_replace += r<EOL>updates_update += u<EOL><DEDENT><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>if BaseCalculator(self.device, child_s, child_o).ne:<EOL><INDENT>d, r, u = self.node_sub(child_s, child_o)<EOL>paths_delete += d<EOL>updates_replace += r<EOL>updates_update += u<EOL><DEDENT><DEDENT><DEDENT><DEDENT>return (paths_delete, updates_replace, updates_update)<EOL>
node_sub

        High-level api: Compute the delta of two config nodes. This method is
        recursive, assuming two config nodes are different.

        Parameters
        ----------

        node_self : `Element`
            A config node in the destination config that is being processed.
            node_self cannot be a leaf node.

        node_other : `Element`
            A config node in the source config that is being processed.

        Returns
        -------

        tuple
            There are three elements in the tuple: a list of gNMI Path
            instances that need to be deleted, a list of gNMI Update instances
            for replacement purpose, and a list of gNMI Update instances for
            merging purpose.