def template_to_descriptor(template: AttributeTemplate, *, headers: List[str]=[]) -> Descriptor:
    '\n    Convert a GEMD attribute template into an AI Engine Descriptor.\n\n    IntBounds cannot be converted because they have no matching descriptor type.\n    CompositionBounds can only be converted when every component is an element, in which case\n    they are converted to ChemicalFormulaDescriptors.\n\n    Parameters\n    ----------\n    template: AttributeTemplate\n        Template to convert into a descriptor\n    headers: List[str]\n        Names of parent relationships to includes as prefixes\n        to the template name in the descriptor key\n        Default: []\n\n    Returns\n    -------\n    Descriptor\n        Descriptor with a key matching the template name and type corresponding to the bounds\n\n    '
    headers = (headers + [template.name])
    descriptor_key = '~'.join(headers)
    bounds = template.bounds
    if isinstance(bounds, RealBounds):
        return RealDescriptor(key=descriptor_key, lower_bound=bounds.lower_bound, upper_bound=bounds.upper_bound, units=bounds.default_units)
    if isinstance(bounds, CategoricalBounds):
        return CategoricalDescriptor(key=descriptor_key, categories=bounds.categories)
    if isinstance(bounds, MolecularStructureBounds):
        return MolecularStructureDescriptor(key=descriptor_key)
    if isinstance(bounds, CompositionBounds):
        if set(bounds.components).issubset(EmpiricalFormula.all_elements()):
            return ChemicalFormulaDescriptor(key=descriptor_key)
        else:
            msg = 'Cannot create descriptor for CompositionBounds with non-atomic components'
            raise NoEquivalentDescriptorError(msg)
    if isinstance(bounds, IntegerBounds):
        raise NoEquivalentDescriptorError('Cannot create a descriptor for integer-valued data')
    raise ValueError('Template has unrecognized bounds: {}'.format(type(bounds)))
Convert a GEMD attribute template into an AI Engine Descriptor.

IntBounds cannot be converted because they have no matching descriptor type.
CompositionBounds can only be converted when every component is an element, in which case
they are converted to ChemicalFormulaDescriptors.

Parameters
----------
template: AttributeTemplate
    Template to convert into a descriptor
headers: List[str]
    Names of parent relationships to includes as prefixes
    to the template name in the descriptor key
    Default: []

Returns
-------
Descriptor
    Descriptor with a key matching the template name and type corresponding to the bounds
def template_to_descriptor(template: AttributeTemplate, *, headers: List[str]=[]) -> Descriptor:
    '\n    Convert a GEMD attribute template into an AI Engine Descriptor.\n\n    IntBounds cannot be converted because they have no matching descriptor type.\n    CompositionBounds can only be converted when every component is an element, in which case\n    they are converted to ChemicalFormulaDescriptors.\n\n    Parameters\n    ----------\n    template: AttributeTemplate\n        Template to convert into a descriptor\n    headers: List[str]\n        Names of parent relationships to includes as prefixes\n        to the template name in the descriptor key\n        Default: []\n\n    Returns\n    -------\n    Descriptor\n        Descriptor with a key matching the template name and type corresponding to the bounds\n\n    '
    headers = (headers + [template.name])
    descriptor_key = '~'.join(headers)
    bounds = template.bounds
    if isinstance(bounds, RealBounds):
        return RealDescriptor(key=descriptor_key, lower_bound=bounds.lower_bound, upper_bound=bounds.upper_bound, units=bounds.default_units)
    if isinstance(bounds, CategoricalBounds):
        return CategoricalDescriptor(key=descriptor_key, categories=bounds.categories)
    if isinstance(bounds, MolecularStructureBounds):
        return MolecularStructureDescriptor(key=descriptor_key)
    if isinstance(bounds, CompositionBounds):
        if set(bounds.components).issubset(EmpiricalFormula.all_elements()):
            return ChemicalFormulaDescriptor(key=descriptor_key)
        else:
            msg = 'Cannot create descriptor for CompositionBounds with non-atomic components'
            raise NoEquivalentDescriptorError(msg)
    if isinstance(bounds, IntegerBounds):
        raise NoEquivalentDescriptorError('Cannot create a descriptor for integer-valued data')
    raise ValueError('Template has unrecognized bounds: {}'.format(type(bounds)))