def update(d1, d2):
    """
    Update dict d1 with properties from d2

    Note
    ----

    Allows deletion of objects with a special ``__delete__`` key
    For any list of dicts new items can be added when updating

    Parameters
    ----------

    d1: dict
        A Python dictionary
    d2: dict
        A Python dictionary that will be used to update any keys with the same name in d1

    Returns
    -------

    dict
        The updated dictionary

    """
    NoneType = type(None)

    if d2.get("__delete__", False):
        return {}

    for k, v in d2.items():
        if isinstance(v, dict):
            if v.get("__delete__", False):
                # allow a __delete__ property to be set to delete objects
                del d1[k]
            else:
                d1[k] = update(d1.get(k, {}), v)
        elif isinstance(v, (tuple, list)) and all(isinstance(li, (NoneType, dict)) for li in v):
            # a list of dicts and/or NoneType
            orig_list = d1.get(k, [])
            new_list = []
            pairs = list(zip_longest(orig_list, v, fillvalue=None))
            for orig_item, new_item in pairs:
                if orig_item is None:
                    orig_item = {}  # can't use {} for fillvalue as only one dict created/modified!
                if new_item is None:
                    new_item = {}

                if new_item.get("__delete__", False):
                    d = None  # orig_list.remove(orig_item) # remove the item to delete
                else:
                    d = update(orig_item, new_item)

                if d is not None:
                    new_list.append(d)
            d1[k] = new_list
        else:
            if k in d1 and v == "__delete__":
                del d1[k]
            else:
                d1[k] = v
    return d1
def update ( d1 , d2 ) : NoneType = type ( None ) if d2 . get ( "__delete__" , False ) : return { } for k , v in d2 . items ( ) : if isinstance ( v , dict ) : if v . get ( "__delete__" , False ) : del d1 [ k ] else : d1 [ k ] = update ( d1 . get ( k , { } ) , v ) elif isinstance ( v , ( tuple , list ) ) and all ( isinstance ( li , ( NoneType , dict ) ) for li in v ) : orig_list = d1 . get ( k , [ ] ) new_list = [ ] pairs = list ( zip_longest ( orig_list , v , fillvalue = None ) ) for orig_item , new_item in pairs : if orig_item is None : orig_item = { } if new_item is None : new_item = { } if new_item . get ( "__delete__" , False ) : d = None else : d = update ( orig_item , new_item ) if d is not None : new_list . append ( d ) d1 [ k ] = new_list else : if k in d1 and v == "__delete__" : del d1 [ k ] else : d1 [ k ] = v return d1
Update dict d1 with properties from d2

    Note
    ----

    Allows deletion of objects with a special ``__delete__`` key
    For any list of dicts new items can be added when updating

    Parameters
    ----------

    d1: dict
        A Python dictionary
    d2: dict
        A Python dictionary that will be used to update any keys with the same name in d1

    Returns
    -------

    dict
        The updated dictionary