def dijkstra(start, end, graph):
    """
    this function takes in a weighted directed graph, a start node, an end node and outputs
    the shortest path from the start node to the end node on that graph
    input:  start - start node
            end - end node
            graph - weighted directed graph
    output: shortest path from start to end node
    """
    if start == end:
        return 0, [start]
    else:
        score = {}
        predecessor = {}
        unmarked_nodes = graph._nodes.copy()
        if start not in graph._nodes or end not in graph._nodes:
            raise SyntaxError(
                'either the start or end node is not in the graph!')
        for node in graph._nodes:
            if node != start:
                score[node] = float('inf')
            else:
                score[node] = 0
        current = start
        while current != end:
            if current in graph._edges:
                for neighbor in graph._edges[current]:
                    new_score = score[current] + graph._weights[current,
                        neighbor]
                    if score[neighbor] > new_score:
                        score[neighbor] = new_score
                        predecessor[neighbor] = current
            unmarked_nodes.remove(current)
            min_node = None
            score[min_node] = float('inf')
            for unmarked in unmarked_nodes:
                if score[unmarked] <= score[min_node]:
                    min_node = unmarked
            current = min_node
        shortest_path = [end]
        if score[end] != float('inf'):
            start_of_suffix = end
            while predecessor[start_of_suffix] != start:
                shortest_path.append(predecessor[start_of_suffix])
                start_of_suffix = predecessor[start_of_suffix]
            shortest_path.append(start)
            shortest_path.reverse()
        else:
            shortest_path = []
    return score[end], shortest_path
