def test_recursive_copy():
    pdcc1 = ParamDict(cca=30)
    pdcc2 = ParamDict(ccb=40)
    pdc1 = ParamDict(a=3, b=4, cc1=pdcc1, cc2=pdcc2)
    pdc2 = ParamDict(c=5, d=6)
    pd1 = ParamDict(c1=pdc1, c2=pdc2)
    pd2 = pd1.copy_recursive()

    assert pd1.c2.d == 6
    assert pd2.c2.d == 6
    pd1.c2.d = 7
    assert pd1.c2.d == 7
    assert pd2.c2.d == 6
    pd2.c2.d = 8
    assert pd1.c2.d == 7
    assert pd2.c2.d == 8

    assert pd1.c1.cc2.ccb == 40
    assert pd2.c1.cc2.ccb == 40
    pd2.c1.cc2.ccb = 50
    assert pd1.c1.cc2.ccb == 40
    assert pd2.c1.cc2.ccb == 50
    pd1.c1.cc2.ccb = 60
    assert pd1.c1.cc2.ccb == 60
    assert pd2.c1.cc2.ccb == 50
def test_recursive_update():
    # Build multilevel test data
    pdcc1 = ParamDict(cca=30)
    pdcc2 = ParamDict(ccb=40)
    pdc1 = ParamDict(a=3, b=4, cc1=pdcc1, cc2=pdcc2)
    pdc2 = ParamDict(c=5, d=6)
    pdorig = ParamDict(c1=pdc1, c2=pdc2, v=7)

    # Build alternative multilevel test data
    apdcc1 = ParamDict(cca=31)
    apdcc2 = ParamDict(ccb=41)
    apdc1 = ParamDict(a=5, b=8, cc1=apdcc1, cc2=apdcc2)
    apdc2 = ParamDict(c=7, d=9)
    apdorig = ParamDict(c1=apdc1, c2=apdc2, v=2)

    assert pdorig != apdorig

    # Supply a single item
    pd = pdorig.copy_recursive()
    assert pd.v == 7
    pd.update_recursive(v=9)
    assert pd.v == 9
    pd.update_recursive({'v': 10})
    assert pd.v == 10
    pd.update_recursive(ParamDict(v=11))
    assert pd.v == 11

    # Supply multiple items for child
    pd = pdorig.copy_recursive()
    assert pd.c1.a == 3
    assert pd.c1.b == 4
    if 0:
        pd.update_recursive(c1={'a': 11, 'b': 22})
        assert pd.c1.a == 11
        assert pd.c1.b == 22
    pd.update_recursive(c1=ParamDict(a=13, b=25))
    assert pd.c1.a == 13
    assert pd.c1.b == 25

    # Supply a full multilevel paramdict
    pd = pdorig.copy_recursive()
    assert pd == pdorig
    assert pd != apdorig
    pd.update_recursive(apdorig)
    assert pd != pdorig
    assert pd == apdorig
def test_shallow_copy():
    pd1 = ParamDict(a=3, b=4)
    pd2 = pd1.copy_recursive()
    pd1.a = 1
    pd2.a = 2
    pd2.b = 2
    pd1.b = 1
    assert pd1.a == 1
    assert pd1.b == 1
    assert pd2.a == 2
    assert pd2.b == 2
def test_recursive_replace():
    # Build multilevel test data
    pdcc1 = ParamDict(cca=30)
    pdcc2 = ParamDict(ccb=40)
    pdc1 = ParamDict(a=3, b=4, cc1=pdcc1, cc2=pdcc2)
    pdc2 = ParamDict(c=5, d=6)
    pdorig = ParamDict(c1=pdc1, c2=pdc2, v=7)

    # Build alternative multilevel test data
    apdcc1 = ParamDict(cca=31)
    apdcc2 = ParamDict(ccb=41)
    apdc1 = ParamDict(a=5, b=8, cc1=apdcc1, cc2=apdcc2)
    apdc2 = ParamDict(c=7, d=9)
    apdorig = ParamDict(c1=apdc1, c2=apdc2, v=2)

    assert pdorig != apdorig

    # Supply a single item
    pd = pdorig.copy_recursive()
    assert pd.v == 7
    pd.replace_recursive(v=9)
    assert pd.v == 9
    pd.replace_recursive({'v': 10})
    assert pd.v == 10
    pd.replace_recursive(ParamDict(v=11))
    assert pd.v == 11

    # Supply multiple items for child
    pd = pdorig.copy_recursive()
    assert pd.c1.a == 3
    assert pd.c1.b == 4
    if 0:
        pd.replace_recursive(c1={'a': 11, 'b': 22})
        assert pd.c1.a == 11
        assert pd.c1.b == 22
    pd.replace_recursive(c1=ParamDict(a=13, b=25))
    assert pd.c1.a == 13
    assert pd.c1.b == 25

    # Supply a full multilevel paramdict
    pd = pdorig.copy_recursive()
    assert pd == pdorig
    assert pd != apdorig
    pd.replace_recursive(apdorig)
    assert pd != pdorig
    assert pd == apdorig

    # Raises for single missing item
    pd = pdorig.copy_recursive()
    with pytest.raises(RuntimeError):
        pd.replace_recursive(v2=13)

    # Build alternative multilevel test data
    rpdcc1 = ParamDict(cca2=32)
    rpdc1 = ParamDict(cc1=rpdcc1)
    rpdorig = ParamDict(c1=rpdc1)

    # Raises for item deep in recursive structure
    pd = pdorig.copy_recursive()
    with pytest.raises(RuntimeError):
        pd.replace_recursive(rpdorig)