import copy


def topological_sort(graph):
    """
    Perform a topological sort on the graph and return a list of sorted nodes.
    The graph is represented as a dictionary where each key is a node and
    the value is a list/set of connected child nodes.
    >>> graph = {
    ...    2 : set([11]),
    ...    9 : set([11, 8]),
    ...    10 : set([11, 3]),
    ...    11 : set([5, 7]),
    ...    8 : set([7, 3]),
    ...    5 : set(),
    ...    7 : set(),
    ...    3 : set()
    ... }
    >>> topological_sort(graph)
    [3, 7, 5, 8, 11, 2, 9, 10]
    """
    # Kahn's Algorithm (https://en.wikipedia.org/wiki/Topological_sorting)
    # L ← Empty list that will contain the sorted elements
    # S ← Set of all nodes with no incoming edges
    # while S is non-empty do
    #     remove a node n from S
    #     add n to tail of L
    #     for each node m with an edge e from n to m do
    #         remove edge e from the graph
    #         if m has no other incoming edges then
    #             insert m into S
    # if graph has edges then
    #     return error (graph has at least one cycle)
    # else
    #     return L (a topologically sorted order)
    # Construct a local shallow copy as we directly manipulate graph values
    graph = dict((k, copy.copy(graph[k])) for k in graph.keys())
    l = []  # noqa
    # using type set() for S breaks ordering between python versions
    s = list([node for node in graph if len(graph[node]) == 0])
    while len(s) > 0:
        n = s.pop()
        l.append(n)
        for m in list(filter(lambda x: n in graph[x], graph.keys())):
            graph[m].remove(n)
            if len(graph[m]) == 0:
                s.insert(0, m)
    if any(len(graph[n]) > 0 for n in graph.keys()):
        raise ValueError('Graph contains at least one cycle')
    else:
        return l