Strongly inspired from idlelib.ColorDelegator.make_pat

def make_python_patterns(additional_keywords=[], additional_builtins=[]):
    "Strongly inspired from idlelib.ColorDelegator.make_pat"
    kwlist = keyword.kwlist + additional_keywords
    builtinlist = [str(name) for name in dir(builtins)
                   if not name.startswith('_')] + additional_builtins
    repeated = set(kwlist) & set(builtinlist)
    for repeated_element in repeated:
        kwlist.remove(repeated_element)
    kw = r"\b" + any("keyword", kwlist) + r"\b"
    builtin = r"([^.'\"\\#]\b|^)" + any("builtin", builtinlist) + r"\b"
    comment = any("comment", [r"#[^\n]*"])
    instance = any("instance", [r"\bself\b",
                                r"\bcls\b",
                                (r"^\s*@([a-zA-Z_][a-zA-Z0-9_]*)"
                                     r"(\.[a-zA-Z_][a-zA-Z0-9_]*)*")])
    number_regex = [r"\b[+-]?[0-9]+[lLjJ]?\b",
                    r"\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b",
                    r"\b[+-]?0[oO][0-7]+[lL]?\b",
                    r"\b[+-]?0[bB][01]+[lL]?\b",
                    r"\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?[jJ]?\b"]
    if PY3:
        prefix = "r|u|R|U|f|F|fr|Fr|fR|FR|rf|rF|Rf|RF|b|B|br|Br|bR|BR|rb|rB|Rb|RB"
    else:
        prefix = "r|u|ur|R|U|UR|Ur|uR|b|B|br|Br|bR|BR"
    sqstring =     r"(\b(%s))?'[^'\\\n]*(\\.[^'\\\n]*)*'?" % prefix
    dqstring =     r'(\b(%s))?"[^"\\\n]*(\\.[^"\\\n]*)*"?' % prefix
    uf_sqstring =  r"(\b(%s))?'[^'\\\n]*(\\.[^'\\\n]*)*(\\)$(?!')$" % prefix
    uf_dqstring =  r'(\b(%s))?"[^"\\\n]*(\\.[^"\\\n]*)*(\\)$(?!")$' % prefix
    sq3string =    r"(\b(%s))?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?" % prefix
    dq3string =    r'(\b(%s))?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?' % prefix
    uf_sq3string = r"(\b(%s))?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(\\)?(?!''')$" \
                   % prefix
    uf_dq3string = r'(\b(%s))?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(\\)?(?!""")$' \
                   % prefix
    # Needed to achieve correct highlighting in Python 3.6+
    # See issue 7324
    if PY36_OR_MORE:
        # Based on
        # https://github.com/python/cpython/blob/
        # 81950495ba2c36056e0ce48fd37d514816c26747/Lib/tokenize.py#L117
        # In order: Hexnumber, Binnumber, Octnumber, Decnumber,
        # Pointfloat + Exponent, Expfloat, Imagnumber
        number_regex = [
                r"\b[+-]?0[xX](?:_?[0-9A-Fa-f])+[lL]?\b",
                r"\b[+-]?0[bB](?:_?[01])+[lL]?\b",
                r"\b[+-]?0[oO](?:_?[0-7])+[lL]?\b",
                r"\b[+-]?(?:0(?:_?0)*|[1-9](?:_?[0-9])*)[lL]?\b",
                r"\b((\.[0-9](?:_?[0-9])*')|\.[0-9](?:_?[0-9])*)"
                "([eE][+-]?[0-9](?:_?[0-9])*)?[jJ]?\b",
                r"\b[0-9](?:_?[0-9])*([eE][+-]?[0-9](?:_?[0-9])*)?[jJ]?\b",
                r"\b[0-9](?:_?[0-9])*[jJ]\b"]
    number = any("number", number_regex)

    string = any("string", [sq3string, dq3string, sqstring, dqstring])
    ufstring1 = any("uf_sqstring", [uf_sqstring])
    ufstring2 = any("uf_dqstring", [uf_dqstring])
    ufstring3 = any("uf_sq3string", [uf_sq3string])
    ufstring4 = any("uf_dq3string", [uf_dq3string])
    return "|".join([instance, kw, builtin, comment,
                     ufstring1, ufstring2, ufstring3, ufstring4, string,
                     number, any("SYNC", [r"\n"])])