def edge_loops_from_tessfaces(mesh, tessfaces=None, seams=()):
    """
    Edge loops defined by faces

    Takes me.tessfaces or a list of faces and returns the edge loops
    These edge loops are the edges that sit between quads, so they dont touch
    1 quad, note: not connected will make 2 edge loops,
    both only containing 2 edges.

    return a list of edge key lists
    [[(0, 1), (4, 8), (3, 8)], ...]

    :arg mesh: the mesh used to get edge loops from.
    :type mesh: :class:`bpy.types.Mesh`
    :arg tessfaces: optional face list to only use some of the meshes faces.
    :type tessfaces: :class:`bpy.types.MeshTessFace`, sequence or or NoneType
    :return: return a list of edge vertex index lists.
    :rtype: list
    """
    OTHER_INDEX = 2, 3, 0, 1
    if tessfaces is None:
        tessfaces = mesh.tessfaces
    edges = {}
    for f in tessfaces:
        if len(f.vertices) == 4:
            edge_keys = f.edge_keys
            for i, edkey in enumerate(f.edge_keys):
                edges.setdefault(edkey, []).append(edge_keys[OTHER_INDEX[i]])
    for edkey in seams:
        edges[edkey] = []
    edge_loops = []
    for edkey, ed_adj in edges.items():
        if 0 < len(ed_adj) < 3:
            context_loop = [edkey, ed_adj[0]]
            edge_loops.append(context_loop)
            if len(ed_adj) == 2:
                other_dir = ed_adj[1]
            else:
                other_dir = None
            del ed_adj[:]
            flipped = False
            while 1:
                ed_adj = edges[context_loop[-1]]
                if len(ed_adj) != 2:
                    if other_dir and flipped is False:
                        flipped = True
                        context_loop.reverse()
                        del ed_adj[:]
                        context_loop.append(other_dir)
                        ed_adj = edges[context_loop[-1]]
                        if len(ed_adj) != 2:
                            del ed_adj[:]
                            break
                    else:
                        del ed_adj[:]
                        break
                i = ed_adj.index(context_loop[-2])
                context_loop.append(ed_adj[not i])
                del ed_adj[:]
    return edge_loops
