<commit_before>"""
Dependency Graph
"""

class Node(object):
    """
    A simple node object for use in a tree graph
    """
    def __init__(self, name):
        """
        Initializes a new node with a specified name.
        The node is not connected to any other nodes.
        
        Key arguments:
            name -- A string consisting of the key identifier
        """
        self.name = name
        self.branches = []
        self.leaves = []
    
    def add_leaf(self, leaf):
        """
        Adds a leaf to the node.
        
        Key arguments:
            leaf -- Another node object
        """
        leaf.branches.append(self)
        self.leaves.append(leaf)
    
    def add_branch(self, branch):
        """
        Adds a branch to the node
        
        Key arguments:
            branch -- Another node object
        """
        self.branches.append(branch)
        branch.leaves.append(self)
    
    def search(self, member):
        """
        Checks if a node is part of this node's tree.
        
        Key arguments:
            member -- A string consisting of the key identifier of a node
        
        Returns:
            If the object is in the tree, returns the object.
            Otherwise, returns None.
        """
        if self.name == member:
            return self
        for i in range(0, len(self.leaves)):
            res = self.leaves[i].search(member)
            if res != None:
                return res
        return None
    
    def return_tree(self, list, visited):
        """
        Return this node's tree.
        
        Key arguments:
            list -- A list to contain the tree (can be non-empty)
        
        Returns:
            list -- The tree of the node appended to the list
        """
        if not (self in visited):
            visited.append(self)
            list.append((self.name, self.leaves))
            for i in range(0, len(self.leaves)):
                self.leaves[i].return_tree(list, visited)
        return list

class DependencyGraph(object):
    """
    Dependency graph built from the bottom and up.
    """
    def __init__(self):
        """
        Creates a new empty dependency graph.
        """
        self.head = Node("HEAD")
        self.endnodes = []
    
    def print_info(self):
        """
        Prints the current independent nodes (if any).
        """
        endnodes = "|"
        if self.endnodes == None:
            endnodes += "None|"
        else:
            for i in range (0, len(self.endnodes)):
                endnodes += self.endnodes[i].name + "|"
        print("Independent nodes: " + endnodes)
    
    def add_independent(self, node):
        """
        Adds a new independent node to the graph.
        
        Key arguments:
            node -- The independent node to be added to the graph
        """
        node.branch = self.head
        self.endnodes.append(node)
        self.head.leaves.append(node)
    
    def add_dependency(self, nodename, depname):
        """
        Adds a new dependency to the graph.
        
        Key arguments:
            nodename: The name of the node that gets a new dependency added.
                      If the node does not exist, it is added to the graph.
            depname: The name of the dependency it should be connected to.
                    It must already be in the tree.
        
        Returns:
            True if the dependency has been created, otherwise False. False
            only occurs when trying to create a dependency to a node that does
            not exist in the graph.
        """
        node = self.head.search(nodename)
        if node == None:
            node = Node(nodename)
        dependency = self.head.search(depname)
        if dependency != None:
            if self.head in dependency.branches:
                self.head.leaves.remove(dependency)
            node.add_branch(dependency.branch)
            node.add_leaf(dependency)
            return True
        else:
            return False
    
    def return_dependencies(self, node):
        """
        Returns a list containing the dependencies of a node one level down.
        
        Key arguments:
            node -- The node to look up dependencies for
        
        Returns:
            list -- A list of the names of all dependencies of the given node
        """ 
        list = []
        for i in range(0, len(node.leaves)):
            list.append(node.leaves[i].name)
        return list
    
    def return_dependencies_str(self, node):
        """
        Returns a string containing the dependencies of a node one level down.<commit_msg>Renamed parts of Node for clarity.<commit_after>"""
Dependency Graph
"""

class Node(object):
    """
    A simple node object for use in a tree graph
    """
    def __init__(self, name):
        """
        Initializes a new node with a specified name.
        The node is not connected to any other nodes.
        
        Key arguments:
            name -- A string consisting of the key identifier
        """
        self.name = name
        self.parents = []
        self.children = []

    def __str__(self):
        return "Node( " + self.name + " )"
    
    def add_child(self, child):
        """
        Adds a child to the node.
        
        Key arguments:
            child -- Another node object
        """
        leaf.parents.append(self)
        self.children.append(leaf)
    
    def add_parent(self, parent):
        """
        Adds a parent to the node
        
        Key arguments:
            parent -- Another node object
        """
        self.parents.append(parent)
        parent.children.append(self)
    
    def search(self, member):
        """
        Checks if a node is part of this node's tree.
        
        Key arguments:
            member -- A string consisting of the key identifier of a node
        
        Returns:
            If the object is in the tree, returns the object.
            Otherwise, returns None.
        """
        if self.name == member:
            return self
        for i in range(0, len(self.leaves)):
            res = self.children[i].search(member)
            if res != None:
                return res
        return None
    
    def return_tree(self, list, visited):
        """
        Return this node's tree.
        
        Key arguments:
            list -- A list to contain the tree (can be non-empty)
        
        Returns:
            list -- The tree of the node appended to the list
        """
        if not (self in visited):
            visited.append(self)
            list.append((self.name, self.children))
            for i in range(0, len(self.children)):
                self.children[i].return_tree(list, visited)
        return list

class DependencyGraph(object):
    """
    Dependency graph built from the bottom and up.
    """
    def __init__(self):
        """
        Creates a new empty dependency graph.
        """
        self.head = Node("HEAD")
        self.endnodes = []
    
    def print_info(self):
        """
        Prints the current independent nodes (if any).
        """
        endnodes = "|"
        if self.endnodes == None:
            endnodes += "None|"
        else:
            for i in range (0, len(self.endnodes)):
                endnodes += self.endnodes[i].name + "|"
        print("Independent nodes: " + endnodes)
    
    def add_independent(self, node):
        """
        Adds a new independent node to the graph.
        
        Key arguments:
            node -- The independent node to be added to the graph
        """
        node.branch = self.head
        self.endnodes.append(node)
        self.head.leaves.append(node)
    
    def add_dependency(self, nodename, depname):
        """
        Adds a new dependency to the graph.
        
        Key arguments:
            nodename: The name of the node that gets a new dependency added.
                      If the node does not exist, it is added to the graph.
            depname: The name of the dependency it should be connected to.
                    It must already be in the tree.
        
        Returns:
            True if the dependency has been created, otherwise False. False
            only occurs when trying to create a dependency to a node that does
            not exist in the graph.
        """
        node = self.head.search(nodename)
        if node == None:
            node = Node(nodename)
        dependency = self.head.search(depname)
        if dependency != None:
            if self.head in dependency.parents:
                self.head.leaves.remove(dependency)
            node.add_branch(dependency.branch)
            node.add_leaf(dependency)
            return True
        else:
            return False
    
    def return_dependencies(self, node):
        """
        Returns a list containing the dependencies of a node one level down.
        
        Key arguments:
            node -- The node to look up dependencies for
        
        Returns:
            list -- A list of the names of all dependencies of the given node
        """ 
        list = []
        for i in range(0, len(node.leaves)):
            list.append(node.leaves[i].name)
        return list
    
    def return_dependencies_str(self, node):
        """
        Returns a string containing the dependencies of a node one level down.
{'fraction_non_alphanumeric': 0.08238155668358714, 'fraction_numerical': 0.0008460236886632825, 'mean_word_length': 1.4919631093544137, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '285034', 'n_tokens_mistral': 2430, 'n_tokens_neox': 2388, 'n_words': 881}