from warnings import warn
from functools import reduce


def add_track_prop_dicts(track_prop_dicts):
    """Adds together multiple track properties dicts of with the same
    properties.

    Args:
        track properties_dicts: a list of track properties dicts with
            the same properties.

    Returns:
        A track properties dictionary with the lists of values of each
        track properties dict in the input list concatenated.

    Raises:
        ValueError: if there is no property shared by all of the track
            property dicts.
    """

    def add_two_track_prop_dicts(tp_so_far, tp_to_add):
        """Adds two track properties dicts together as per rules in
        parent function. Returns the sum."""

        props_in_common = set(tp_so_far.keys()).intersection(
                set(tp_to_add.keys()))

        if props_in_common != set(tp_to_add.keys()):
            warn("Track property dicts have differing value lists. "
                    "Will add only properties in common: {}"
                    .format(props_in_common), UserWarning)

        if not len(props_in_common):
            raise ValueError("Track property dicts to add have no properties "
                    "in common.")

        return dict(map(lambda track_property:
            (track_property,
                tp_so_far[track_property] + tp_to_add[track_property]),
            props_in_common))

    return reduce(add_two_track_prop_dicts, track_prop_dicts)