<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def alter_edge(self, from_index, to_index, new_weight=None, new_edge_properties=None):
 """ Alters either the weight or the edge_properties of an edge in the MoleculeGraph. :param from_index: int :param to_index: int :param new_weight: alter_edge does not require that weight be altered. As such, by default, this is None. If weight is to be changed, it should be a float. :param new_edge_properties: alter_edge does not require that edge_properties be altered. As such, by default, this is None. If any edge properties are to be changed, it should be a dictionary of edge properties to be changed. :return: """


        existing_edge = self.graph.get_edge_data(from_index, to_index)

        # ensure that edge exists before attempting to change it
        if not existing_edge:
            raise ValueError("Edge between {} and {} cannot be altered;\
                                no edge exists between those sites.".format(
                                from_index, to_index
                                ))

        # Third index should always be 0 because there should only be one edge between any two nodes
        if new_weight is not None:
            self.graph[from_index][to_index][0]['weight'] = new_weight

        if new_edge_properties is not None:
            for prop in list(new_edge_properties.keys()):
                self.graph[from_index][to_index][0][prop] = new_edge_properties[prop]