def expand_attribute_strings(<EOL>attribute_strings,<EOL>quote_char='<STR_LIT>',<EOL>missing_value="<STR_LIT>",<EOL>usecols=None):
n = len(attribute_strings)<EOL>extra_columns = {}<EOL>column_order = []<EOL>column_interned_strings = {}<EOL>value_interned_strings = {}<EOL>for (i, attribute_string) in enumerate(attribute_strings):<EOL><INDENT>for kv in attribute_string.split("<STR_LIT:;>"):<EOL><INDENT>parts = kv.strip().split("<STR_LIT:U+0020>", <NUM_LIT:2>)[:<NUM_LIT:2>]<EOL>if len(parts) != <NUM_LIT:2>:<EOL><INDENT>continue<EOL><DEDENT>column_name, value = parts<EOL>try:<EOL><INDENT>column_name = column_interned_strings[column_name]<EOL><DEDENT>except KeyError:<EOL><INDENT>column_name = intern(str(column_name))<EOL>column_interned_strings[column_name] = column_name<EOL><DEDENT>if usecols is not None and column_name not in usecols:<EOL><INDENT>continue<EOL><DEDENT>try:<EOL><INDENT>column = extra_columns[column_name]<EOL><DEDENT>except KeyError:<EOL><INDENT>column = [missing_value] * n<EOL>extra_columns[column_name] = column<EOL>column_order.append(column_name)<EOL><DEDENT>value = value.replace(quote_char, "<STR_LIT>") if value.startswith(quote_char) else value<EOL>try:<EOL><INDENT>value = value_interned_strings[value]<EOL><DEDENT>except KeyError:<EOL><INDENT>value = intern(str(value))<EOL>value_interned_strings[value] = value<EOL><DEDENT>old_value = column[i]<EOL>if old_value is missing_value:<EOL><INDENT>column[i] = value<EOL><DEDENT>else:<EOL><INDENT>column[i] = "<STR_LIT>" % (old_value, value)<EOL><DEDENT><DEDENT><DEDENT>logging.info("<STR_LIT>" % column_order)<EOL>return OrderedDict(<EOL>(column_name, extra_columns[column_name])<EOL>for column_name in column_order)<EOL>
The last column of GTF has a variable number of key value pairs
of the format: "key1 value1; key2 value2;"
Parse these into a dictionary mapping each key onto a list of values,
where the value is None for any row where the key was missing.

Parameters
----------
attribute_strings : list of str

quote_char : str
    Quote character to remove from values

missing_value : any
    If an attribute is missing from a row, give it this value.

usecols : list of str or None
    If not None, then only expand columns included in this set,
    otherwise use all columns.

Returns OrderedDict of column->value list mappings, in the order they
appeared in the attribute strings.