def _reconstruct(keyvals, dialect, keep_order=False,
                 sort_attribute_values=False):
    if not dialect:
        raise AttributeStringError()
    if not keyvals:
        return ""
    parts = []

    # May need to split multiple values into multiple key/val pairs
    if dialect['repeated keys']:
        items = []
        for key, val in keyvals.items():
            if len(val) > 1:
                for v in val:
                    items.append((key, [v]))
            else:
                items.append((key, val))
    else:
        items = list(keyvals.items())

    def sort_key(x):
        # sort keys by their order in the dialect; anything not in there will
        # be in arbitrary order at the end.
        try:
            return dialect['order'].index(x[0])
        except ValueError:
            return 1e6

    if keep_order:
        items.sort(key=sort_key)

    for key, val in items:

        # Multival sep is usually a comma:
        if val:
            if sort_attribute_values:
                val = sorted(val)

            val_str = dialect['multival separator'].join(val)

            if val_str:

                # Surround with quotes if needed
                if dialect['quoted GFF2 values']:
                    val_str = '"%s"' % val_str

                # Typically "=" for GFF3 or " " otherwise
                part = dialect['keyval separator'].join([key, val_str])
        else:
            part = key
        parts.append(part)

    # Typically ";" or "; "
    parts_str = dialect['field separator'].join(parts)

    # Sometimes need to add this
    if dialect['trailing semicolon']:
        parts_str += ';'

    return parts_str


# TODO:
# Cythonize -- profiling shows that the bulk of the time is spent on this
# function...
Returns the text rendered by the Creole markup.
dataset/ETHPy150Open daler/gffutils/gffutils/parser.py/_reconstruct--crossover with--dataset/ETHPy150Open brosner/django-wikiapp/wiki/templatetags/creole.py/creole