def lookupKerningValue(
    pair, kerning, groups, fallback=0, glyphToFirstGroup=None, glyphToSecondGroup=None
):
    """
    Note: This expects kerning to be a flat dictionary
    of kerning pairs, not the nested structure used
    in kerning.plist.

    >>> groups = {
    ...     "public.kern1.O" : ["O", "D", "Q"],
    ...     "public.kern2.E" : ["E", "F"]
    ... }
    >>> kerning = {
    ...     ("public.kern1.O", "public.kern2.E") : -100,
    ...     ("public.kern1.O", "F") : -200,
    ...     ("D", "F") : -300
    ... }
    >>> lookupKerningValue(("D", "F"), kerning, groups)
    -300
    >>> lookupKerningValue(("O", "F"), kerning, groups)
    -200
    >>> lookupKerningValue(("O", "E"), kerning, groups)
    -100
    >>> lookupKerningValue(("O", "O"), kerning, groups)
    0
    >>> lookupKerningValue(("E", "E"), kerning, groups)
    0
    >>> lookupKerningValue(("E", "O"), kerning, groups)
    0
    >>> lookupKerningValue(("X", "X"), kerning, groups)
    0
    >>> lookupKerningValue(("public.kern1.O", "public.kern2.E"),
    ...     kerning, groups)
    -100
    >>> lookupKerningValue(("public.kern1.O", "F"), kerning, groups)
    -200
    >>> lookupKerningValue(("O", "public.kern2.E"), kerning, groups)
    -100
    >>> lookupKerningValue(("public.kern1.X", "public.kern2.X"), kerning, groups)
    0
    """
    # quickly check to see if the pair is in the kerning dictionary
    if pair in kerning:
        return kerning[pair]
    # create glyph to group mapping
    if glyphToFirstGroup is not None:
        assert glyphToSecondGroup is not None
    if glyphToSecondGroup is not None:
        assert glyphToFirstGroup is not None
    if glyphToFirstGroup is None:
        glyphToFirstGroup = {}
        glyphToSecondGroup = {}
        for group, groupMembers in groups.items():
            if group.startswith("public.kern1."):
                for glyph in groupMembers:
                    glyphToFirstGroup[glyph] = group
            elif group.startswith("public.kern2."):
                for glyph in groupMembers:
                    glyphToSecondGroup[glyph] = group
    # get group names and make sure first and second are glyph names
    first, second = pair
    firstGroup = secondGroup = None
    if first.startswith("public.kern1."):
        firstGroup = first
        first = None
    else:
        firstGroup = glyphToFirstGroup.get(first)
    if second.startswith("public.kern2."):
        secondGroup = second
        second = None
    else:
        secondGroup = glyphToSecondGroup.get(second)
    # make an ordered list of pairs to look up
    pairs = [
        (first, second),
        (first, secondGroup),
        (firstGroup, second),
        (firstGroup, secondGroup),
    ]
    # look up the pairs and return any matches
    for pair in pairs:
        if pair in kerning:
            return kerning[pair]
    # use the fallback value
    return fallback


if __name__ == "__main__":
    import doctest

    doctest.testmod()
