def drug_timelines(
        drug_events_df: DataFrame,
        event_lasts_for: datetime.timedelta,
        patient_colname: str = DEFAULT_PATIENT_COLNAME,
        event_datetime_colname: str = DEFAULT_DRUG_EVENT_DATETIME_COLNAME) \
        -> Dict[Any, IntervalList]:
    """
    Takes a set of drug event start times (one or more per patient), plus a
    fixed time that each event is presumed to last for, and returns an
    :class:`IntervalList` for each patient representing the set of events
    (which may overlap, in which case they will be amalgamated).

    Args:
        drug_events_df:
            pandas :class:`DataFrame` containing the event data
        event_lasts_for:
            when an event occurs, how long is it assumed to last for? For
            example, if a prescription of lithium occurs on 2001-01-01, how
            long is the patient presumed to be taking lithium as a consequence
            (e.g. 1 day? 28 days? 6 months?)
        patient_colname:
            name of the column in ``drug_events_df`` containing the patient ID
        event_datetime_colname:
            name of the column in ``drug_events_df`` containing the date/time
            of each event

    Returns:
        dict: mapping patient ID to a :class:`IntervalList` object indicating
        the amalgamated intervals from the events

    """
    sourcecolnum_pt = drug_events_df.columns.get_loc(patient_colname)
    sourcecolnum_when = drug_events_df.columns.get_loc(event_datetime_colname)
    timelines = defaultdict(IntervalList)
    nrows = len(drug_events_df)
    for rowidx in range(nrows):
        patient_id = drug_events_df.iat[rowidx, sourcecolnum_pt]
        event_when = drug_events_df.iat[rowidx, sourcecolnum_when]
        interval = Interval(event_when, event_when + event_lasts_for)
        ivlist = timelines[patient_id]  # will create if unknown
        ivlist.add(interval)
    return timelines