import string


def apply_object_attributes_to_template(template, value_object):
    """Generate a string from the template by applying values from the given object.

    If the template provided is not a template (not have any placeholders), this will not have any effect and template
    will be returned unchanged.
    If value_object is None, this will not have any effect.

    Arguments:
    template        -- A string that may or may not be templated.
                       If templated, the placeholders will be populated with values from the attributes of the
                       value_object.
    value_object    -- Any object that supports the __dict__ method. Most classes have a __dict__ method that return a
                       mapping of all the attributes and the associated values.

    Returns:
    string          -- This will be the template, with the values from value_object applied.
    """
    # Parse the template and extract the field names.
    # We'll use the field names to explicitly look-up attributes in the value_object.
    # The reason for this is that it works for @property attributes as well as normal attributes.
    field_names = [field_name for _, field_name, _, _ in string.Formatter().parse(template) if field_name is not None]

    template_values = {}
    for field_name in field_names:
        try:
            template_values[field_name] = getattr(value_object, field_name)
        except AttributeError as e:
            raise AttributeError(('Unable to apply object to template. Could not look-up attribute \'{}\' in the '
                                  'object \'{}\'. Error: {}').format(field_name, str(value_object), str(e)))
    return template.format(**template_values)