def test_refer_parent_error(): """ A---B-------foo | | | +---bar --> A D """ import modelx as mx m = mx.new_model() A = mx.new_space('A') B = A.new_space('B') @mx.defcells def foo(x): return x B.set_ref("bar", A, "relative") with pytest.raises(ValueError): D = m.new_space('D', bases=B)
def test_refer_parent(mode): """ A---B-------foo | | | +---bar --> A D """ import modelx as mx m = mx.new_model() A = mx.new_space('A') B = A.new_space('B') @mx.defcells def foo(x): return x B.set_ref("bar", A, mode) D = m.new_space('D', bases=B) assert D.bar is A
def dynref_model(): """ A---B---C---foo <-+ | | | | +---bar --+ | D[a]--baz <- D.C """ m = mx.new_model() A = mx.new_space('A') B = A.new_space('B') C = B.new_space('C') @mx.defcells def foo(x): return x D = m.new_space('D') D.add_bases(B) D.parameters = ('a', ) return m
def refmode_model(): """ A---B---C---foo <-+ | | | | +---bar --+ D """ import modelx as mx m = mx.new_model() A = mx.new_space('A') B = A.new_space('B') C = B.new_space('C') @mx.defcells def foo(x): return x D = m.new_space('D') D.add_bases(B) return m
def multiple_prams(request, tmp_path): range_, orientation = request.param model, space = mx.new_model(), mx.new_space() space.new_cells_from_excel( book=XL_TESTDATA, range_=range_, sheet="TestTables", names_row=0, param_cols=[0, 1], param_order=[0, 1], transpose=orientation, ) mx.write_model(model, tmp_path) m2 = mx.read_model(tmp_path) # Write twice to check copy from renamed backup. mx.write_model(m2, tmp_path) target = mx.read_model(tmp_path).spaces[space.name] return space, target
def build_sample_dynamic_model(): """2 level multi-base dynamic space model""" model = mx.new_model(name="sample_dynamic_model") base1 = model.new_space(name="Base1") base2 = model.new_space(name="Base2") base1.new_cells(formula=cells1) base2.new_cells(formula=cells2) parent = model.new_space(name="Parent", formula=parent_param) child = base2.new_space(name="Child", formula=child_param) child.new_space(name="ChildBase1").new_cells(formula=cells3) child.new_space(name="ChildBase2").new_cells(formula=cells4) parent.Base1 = base1 parent.Base2 = base2 return model
def test_update_global_in_space_formula(): """ m-----SpaceA |-x1 | --SpaceA[y]----x3 == m.x1 """ m = mx.new_model() s = m.new_space("SpaceA") def param(y): return {'refs': {'x3': x1}} s.formula = param m.x1 = 3 assert s[1].x3 == 3 m.x1 = 4 assert not s.itemspaces assert s[1].x3 == 4
def extra_params(request, tmp_path): range_, orientation = request.param model = mx.new_model() space = model.new_space_from_excel( book=XL_TESTDATA, range_=range_, sheet="TestSpaceTables", name="TestSpace", names_row=0, param_cols=[0, 1], names_col=1, param_rows=[1], space_param_order=[1], cells_param_order=[2, 0], transpose=orientation, ) mx.write_model(model, tmp_path) target = mx.read_model(tmp_path) return model, target
def test_change_attrref(): m = mx.new_model() s = m.new_space() @mx.defcells def foo(x): return bar.x @mx.defcells def qux(y): return bar[1].x s2 = mx.new_space("bar", formula=lambda a: None) s.bar = s2 s2.x = "bar" assert foo(3) == qux(3) == "bar" s2.x = "baz" assert foo(3) == qux(3) == "baz"
def no_values(): model = mx.new_model("Model") space = model.new_space("Space") @defcells def param0(): return 0 @defcells def param1(x): return x @defcells def param2(x, y): return x * y space.formula = lambda i: None yield space model.close()
def test_consecutive_writes(tmp_path, save_meth): m = mx.new_model() s = m.new_space("SpaceA") kwargs = testargs[0].copy() expected = kwargs.pop("expected") kwargs["path"] = "files/testexcel.xlsx" kwargs["sheet"] = "TestTables" kwargs["loadpath"] = XL_TESTDATA s.new_excel_range(**kwargs) getattr(m, save_meth)(tmp_path / "model") getattr(m, save_meth)(tmp_path / "model") m.close() m2 = mx.read_model(tmp_path / "model") assert m2.SpaceA.table1 == expected m2.close()
def test_circler_nonerror(): """ C |-+ A <-D | | | B --->E """ model = mx.new_model() A = model.new_space("A") B = A.new_space("B") C = model.new_space("C") D = C.new_space("D") E = C.new_space("E") A.add_bases(D) E.add_bases(B) assert A.bases == [D] assert E.bases == [B]
def test_nested_globals(): """Globals used in generator and nested function""" def foo(): return list(gvar * i for i in (0, 1, 2)) def bar(): def inner(): return gvar return inner() s = mx.new_model().new_space() s.gvar = 1 s.new_cells(formula=foo) s.new_cells(formula=bar) for cells in [s.foo, s.bar]: cells() node = cells.precedents()[0] assert node.obj.name == 'gvar' assert node.obj.value == 1
def precedstest(): m = mx.new_model('Preceds') space = m.new_space('Space1') space.new_space('Child') space.Child.new_space('GrandChild') space.x = 1 space.Child.y = 2 space.Child.GrandChild.z = 3 @mx.defcells(space=space) def foo(t): return t @mx.defcells(space=space) def bar(t): return foo(t) + x + Child.y + Child.GrandChild.z space.bar(3) return space
def test_refer_sibling(mode): """ A---B-------foo <-+ | | | | +---bar --+ D """ import modelx as mx m = mx.new_model() A = mx.new_space('A') B = A.new_space('B') @mx.defcells def foo(x): return x B.set_ref("bar", foo, mode) D = m.new_space('D', bases=B) assert D.bar is D.foo
def test_new_del_basemember_lv4ly2(atavistic): """ A <--B | | C(*) C | | D(*) D | | E* E """ model = mx.new_model() B = model.new_space("B") E = B.new_space("C").new_space("D").new_space("E") A = model.new_space("A") if atavistic: D = A.new_space("C").new_space("D") A.add_bases(B) assert "E" in A.spaces["C"].spaces["D"].spaces del B.spaces["C"].spaces["D"].spaces["E"] assert "E" not in A.spaces["C"].spaces["D"].spaces
def pickletest(): """ TestModel---SpaceA-----foo(x) +--lambdacells(x) | +--SpaceB--ou = [o, u] | +--o = list +--u = dict +--iflist = [foo, SpaceB, TestModel] +--ifwrap = InterfaceWrapper(foo, SpaceB, TestModel) """ m, s = mx.new_model("TestModel"), mx.new_space(name='SpaceA') @mx.defcells def foo(x): # Comment return x # Comment c = s.new_cells(name="lambdacells", formula=lambda x: 2 * x) s.another_space = m.new_space(name="SpaceB") # modelx objects in other objects s.iflist = [foo, s.another_space, m] s.ifwrap = InterfaceWrapper(foo, s.another_space, m) # same objects s.o = [1, "2"] s.u = {3: '4', '5': ['6', 7]} s.another_space.ou = [s.o, s.u] # Cells input data foo[0] = 0 foo[1] = m c[0] = "123" c[s] = 3 return m
def test_single_param(tmp_path): m, s = mx.new_model(), mx.new_space() s.new_cells_from_csv(filepath=CSV_SINGLE_PARAM, cells=None, param=None, index_col=0) modelpath = tmp_path / "csv_single_param" mx.write_model(m, modelpath) assert modelpath.joinpath(CSV_SINGLE_PARAM.name).exists() m2 = mx.read_model(modelpath) # Compare components compare_model(m, m2) # Compare values trg = m2.spaces[s.name] for cells, offset in zip(["Cells1", "Cells2"], [1000, 2000]): assert trg.cells[cells].parameters == ("Param", ) for param in range(16): assert trg.cells[cells](param) == offset + param
def test_del_global_attrref(): """ m-----SpaceA-----foo +--SpaceB +--s2 +--x """ m = mx.new_model() s = mx.new_space("SpaceA") @mx.defcells def foo(i): return s2.x s2 = mx.new_space(name="SpaceB", formula=lambda a: None) s.s2 = s2 m.x = 3 assert foo(3) == 3 del m.x with SuppressFormulaError(): with pytest.raises(AttributeError): foo(3)
def derived_relref(): """ Base----Child-------GChild----GGChild---Ref<-Child/GChild | Sub-----SubChild----SubGChild | GSub---GSubChild """ import modelx as mx m = mx.new_model() GGChild = m.new_space('Base').new_space('Child').new_space( 'GChild').new_space('GGChild') SubGChild = m.new_space('Sub').new_space('SubChild').new_space('SubGChild') GSubChild = m.new_space('GSub').new_space('GSubChild') SubGChild.add_bases(m.Base.Child.GChild) GSubChild.add_bases(m.Sub.SubChild) return m
def extra_params(request, tmp_path): range_, orientation, write_method = request.param model, space = mx.new_model(), mx.new_space() space.new_cells_from_excel( book=XL_TESTDATA, range_=range_, sheet="TestTables", names_row=0, param_cols=[0], names_col=0, param_rows=[1], param_order=[1, 0], transpose=orientation, ) getattr(mx, write_method)(model, tmp_path) m2 = mx.read_model(tmp_path) # Write twice to check copy from renamed backup. getattr(mx, write_method)(m2, tmp_path) target = mx.read_model(tmp_path).spaces[space.name] return space, target
def consts(request, tmp_path): range_, orientation, write_method = request.param model = mx.new_model() space = model.new_space_from_excel( book=XL_TESTDATA, range_=range_, sheet="TestSpaceTables", name="TestSpace", names_row=0, param_cols=[0], space_param_order=[0], cells_param_order=[], transpose=orientation, ) getattr(mx, write_method)(model, tmp_path) # Write twice to check copy from renamed backup. m2 = mx.read_model(tmp_path) getattr(mx, write_method)(m2, tmp_path) target = mx.read_model(tmp_path) return model, target
def test_copy(name): """ Before: Base<------Sub Source[a] | foo After: Base<------Sub | | Source Source* | | foo foo* """ base = mx.new_model().new_space("Base") sub = mx.new_space(bases=base) source = mx.new_space("Source") @mx.defcells(source) def foo(x): return x * a source.parameters = ("a", ) source.a = 1 source.foo[0] = 1 target = source.copy(base, name) name = name or source.name assert target is base.spaces[name] assert base.spaces[name].foo[0] == 1 assert base.spaces[name].foo[1] == 1 assert sub.spaces[name].foo[0] == 0 assert sub.spaces[name].foo[1] == 1 assert base.spaces[name][2].foo[1] == 2 assert sub.spaces[name][2].foo[1] == 2
def testmodel(): """ base.x | +----base[1].x sub.x (derived) | +----sub[1].x gsub.x (defined) """ m, base = mx.new_model(), mx.new_space("base") base.formula = lambda i: None base.x = 1 sub = mx.new_space("sub", bases=base) sub.formula = base.formula gsub = mx.new_space("gsub", bases=sub) assert base(1).x == 1 assert sub(1).x == 1 gsub.x = 3 # defined return m
def sample_for_rename_and_formula(): """Test model for rename and set_formula model-----Parent---Child1---Foo # rename to Baz | | | +-Child2---Bar | +--Sub1 <- Parent | +--Sub2[a] <- {1:Child1, *:Child2} """ model = mx.new_model() parent = model.new_space('Parent') child1 = parent.new_space('Child1') child2 = parent.new_space('Child2') foo = child1.new_cells('Foo', formula=lambda x: x) bar = child2.new_cells('Bar', formula=lambda x: x) sub1 = model.new_space('Sub1', bases=parent) def _param(a): b = Parent.Child1 if a == 1 else Parent.Child2 return {'bases': b} sub2 = model.new_space('Sub2', formula=_param) sub2.Parent = parent foo(1) bar(1) sub2[1].Foo(1) sub2[2].Bar(1) model.Sub1.Child1.Foo(1) assert tuple(sub1.Child1.cells) == ("Foo", ) assert len(sub1.Child1.Foo) == 1 assert tuple(sub2.itemspaces) == (1, 2) return model
def test_recalc_dynamic(): """ m---base[i]---child[j]---baz(y) | +---foo(x) +-qux | +---bar +-sub(base)[j] """ m = mx.new_model() base = mx.new_space("base", formula=lambda i: None) sub = mx.new_space("sub", bases=base, formula=lambda j: None) child = base.new_space("child", formula=lambda k: None) def foo(x): return bar def baz(y): return qux child.qux = 30 base.new_cells(formula=foo) child.new_cells(formula=baz) base.bar = 3 assert base[3].foo(1) == 3 base.bar = 4 assert base[3].foo(1) == 4 assert sub[3].child.qux == 30 assert sub[3].child[2].qux == 30 assert sub[3].child[2].baz(4) == 30 base.child.qux = 40 assert sub[3].child.qux == 40 assert sub[3].child[2].qux == 40 assert sub[3].child[2].baz(4) == 40
def test_add_remove_bases_lv4ly2(atavistic): """ atavistic: True atavistic: False start/end start/end A B A B | | | C C C | | | D D D | | E E add_bases add_base A <--B A <--B | | | | C C C* C | | | | D D D* D | | | | E* E E* E remove_bases remove_bases """ model = mx.new_model() B = model.new_space("B") E = B.new_space("C").new_space("D").new_space("E") A = model.new_space("A") if atavistic: A.new_space("C").new_space("D") A.add_bases(B) assert "E" in A.spaces["C"].spaces["D"].spaces A.remove_bases(B) if atavistic: assert "E" not in A.spaces["C"].spaces["D"].spaces else: assert "C" not in A.spaces
def testmodel(): """ TestModel-----TestSpace[a]-----foo | +--m = 1 +--n = "abc" +--t = nested sequences +--u = dict +--v = TestModel +--w = foo | +--Another +s = Another """ m, s = mx.new_model("TestModel"), mx.new_space(name='TestSpace') @mx.defcells def foo(x): # Comment return x # Comment s.formula = lambda a: None s.m = 1 s.n = "abc" s.o = [1, "2"] s.t = (1, 2, "藍上夫", (3, 4.33), [5, None, (7, 8, [9, 10], "ABC")]) s.u = {3: '4', '5': ['6', 7]} # modelx objects as refs s.v = m s.w = foo an = m.new_space(name="Another") s.s = an return m
def test_remove_bases_shared_subs(): """ A <- B -> C | | | X X* X | | | M M*N* N """ m = mx.new_model() m.new_space("A").new_space("X").new_cells("M") m.new_space("B") m.new_space("C").new_space("X").new_cells("N") A = m.A B = m.B C = m.C B.add_bases(A, C) B.remove_bases(A) assert hasattr(B, "X") assert hasattr(B.X, "N") assert not hasattr(B.X, "M") print(hasattr(B.X, "N"))
def test_multiple_params(tmp_path): m, s = mx.new_model(), mx.new_space() s.new_cells_from_csv(filepath=CSV_MULTI_PARAMS, cells=None, param=None, index_col=[0, 1]) modelpath = tmp_path / "csv_mult_params" mx.write_model(m, modelpath) assert modelpath.joinpath(CSV_MULTI_PARAMS.name).exists() m2 = mx.read_model(modelpath) # Compare components compare_model(m, m2) # Compare values trg = m2.spaces[s.name] for cells, offset in zip(["Cells1", "Cells2"], [1000, 2000]): assert trg.cells[cells].parameters == ("Param1", "Param2") for param in range(16): assert trg.cells[cells](param, param + 100) == offset + param