docs: def add_hypernode(self, hypernode, composing_nodes=set(), attr_dict=None, **attr):
          """Adds a hypernode to the graph, along with any related attributes
             of the hypernode.
  
          :param hypernode: reference to the hypernode being added.
          :param nodes: reference to the set of nodes that compose
          			the hypernode.
          :param in_hypernodes: set of references to the hypernodes that the
          			node being added is a member of.
          :param attr_dict: dictionary of attributes of the node.
          :param attr: keyword arguments of attributes of the node;
                      attr's values will override attr_dict's values
                      if both are provided.
  
          """
          attr_dict = self._combine_attribute_arguments(attr_dict, attr)
  
          # If the hypernode hasn't previously been added, add it along
          # with its attributes
          if not self.has_hypernode(hypernode):
          	attr_dict["__composing_nodes"] = composing_nodes
          	added_nodes = composing_nodes
          	removed_nodes = set()
              self._hypernode_attributes[hypernode] = attr_dict
          # Otherwise, just update the hypernode's attributes
          else:
              self._hypernode_attributes[hypernode].update(attr_dict)
              added_nodes = composing_nodes - self._hypernode_attributes\
              			  [hypernode]["__composing_nodes"]
  			removed_nodes = self._hypernode_attributes\
              			  	[hypernode]["__composing_nodes"] - composing_nodes
          
          # For every "composing node" added to this hypernode, update
          # those nodes attributes to be members of this hypernode
  		for node in added_nodes:
  			_add_hypernode_membership(node, hypernode)
  		# For every "composing node" added to this hypernode, update
          # those nodes attributes to no longer be members of this hypernode
          for node in remove_nodes:
  			_remove_hypernode_membership(node, hypernode)