def render_string(string, sub):
    """
    string: a string, containing formatting instructions
    sub: a dictionary containing keys and values to substitute for
        them.

    returns: string % sub

    The only difference between this function and the % operator
    is that it raises an exception with a more informative error
    message than the % operator does.
    """
    try:
        finalCode = string % sub
    except Exception as E:
        # If unable to render the string, render longer and longer
        # initial substrings until we find the minimal initial substring
        # that causes an error
        i = 0
        while i <= len(string):
            try:
                finalCode = string[0:i] % sub
            except Exception as F:
                if str(F) == str(E):
                    raise Exception(string[0:i] + "<<<< caused exception " + str(F))
            i += 1
        raise AssertionError()
    return finalCode


def pretty_format(string):
    lines = string.split("\n")

    lines = [strip_leading_white_space(line) for line in lines]

    indent = 0
    for i in range(len(lines)):
        indent -= lines[i].count("}")
        if indent < 0:
            indent = 0
        #
        lines[i] = ("    " * indent) + lines[i]
        indent += lines[i].count("{")
    #

    rval = "\n".join(lines)

    return rval


def strip_leading_white_space(line):
    while len(line) > 0 and (line[0] == " " or line[0] == "\t"):
        line = line[1:]
    return line
