def assoc_in(d, keys, value, factory = dict):
    """ Update value in a (potentially) nested dictionary

    This function was inspired by toolz.update_in and adopted for bazel.

    Source:
        https://github.com/pytoolz/toolz/blob/master/toolz/dicttoolz.py

    Args:
        d: dictionary on which to operate
        keys: list or tuple giving the location of the value to be changed in d
        value: function to operate on that value
        factory: function at

    Returns:
        If keys == [k0,..,kX] and d[k0]..[kX] == v, update_in returns a copy of the
        original dictionary with v replaced by func(v), but does not mutate the
        original dictionary.

        If k0 is not a key in d, update_in creates nested dictionaries to the depth
        specified by the keys, with the innermost value set to func(default).

        >>> inc = lambda x: x + 1
        >>> update_in({'a': 0}, ['a'], inc)
        {'a': 1}

        >>> transaction = {'name': 'Alice',
        ...                'purchase': {'items': ['Apple', 'Orange'],
        ...                             'costs': [0.50, 1.25]},
        ...                'credit card': '5555-1234-1234-1234'}
        >>> update_in(transaction, ['purchase', 'costs'], sum) # doctest: +SKIP
        {'credit card': '5555-1234-1234-1234',
        'name': 'Alice',
        'purchase': {'costs': 1.75, 'items': ['Apple', 'Orange']}}

        >>> # updating a value when k0 is not in d
        >>> update_in({}, [1, 2, 3], str, default="bar")
        {1: {2: {3: 'bar'}}}
        >>> update_in({1: 'foo'}, [2, 3, 4], inc, 0)
        {1: 'foo', 2: {3: {4: 1}}}
    """

    k = keys[0]

    rv = factory()
    inner = rv

    rv.update(d)

    for key in keys[1:]:
        if k in d:
            d = d[k]
            dtemp = factory()
            dtemp.update(d)
        else:
            d = factory()
            dtemp = d

        inner[k] = dtemp
        inner = inner[k]
        k = key

    if k in d:
        inner[k] = value
    else:
        inner[k] = value
    return rv