From 70bdf7082ac3576115071e594d0afeb5c1262224 Mon Sep 17 00:00:00 2001 From: Fumito Hamamura Date: Sat, 13 Jul 2024 13:36:31 +0900 Subject: [PATCH] ENH: Add _parent in namespace --- modelx/core/space.py | 3 +- modelx/tests/core/space/test_space.py | 10 ++++- modelx/tests/export/test_export.py | 54 +++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/modelx/core/space.py b/modelx/core/space.py index 8ce54f8..8638cd1 100644 --- a/modelx/core/space.py +++ b/modelx/core/space.py @@ -1377,7 +1377,8 @@ def __init__( self._cells = CellsDict("cells", self) self._named_spaces = SpaceDict("named_spaces", self) self._sys_refs = LazyEvalDict("sys_refs", - {"_self": self, "_space": self, "_model": self.model}) + {"_self": self, "_space": self, + "_model": self.model, "_parent": self.parent}) self._refs = self._init_refs(arguments) NamespaceServer.__init__( diff --git a/modelx/tests/core/space/test_space.py b/modelx/tests/core/space/test_space.py index fe4cdf2..5585f09 100644 --- a/modelx/tests/core/space/test_space.py +++ b/modelx/tests/core/space/test_space.py @@ -11,6 +11,7 @@ def testmodel(): model, space = new_model(name="testmodel"), new_space(name="testspace") + space.parameters = ("a",) @defcells(space) def foo(x): @@ -19,6 +20,10 @@ def foo(x): else: return foo(x - 1) + @defcells(space) + def get_parent(): + return _parent + space.bar = 3 yield model @@ -31,13 +36,16 @@ def test_refs(testmodel): def test_dir(testmodel): - assert {"foo", "bar", "_self", "_space", "__builtins__", "_model"} == set( + assert {"foo", "bar", "get_parent", + "_self", "_space", "__builtins__", "_model", "_parent"} == set( dir(testmodel.testspace) ) def test_parent(testmodel): assert cur_space().parent == testmodel + assert cur_space().get_parent == testmodel + assert cur_space()[1].get_parent == cur_space() def test_create(testmodel): diff --git a/modelx/tests/export/test_export.py b/modelx/tests/export/test_export.py index 7e274c0..5073fee 100644 --- a/modelx/tests/export/test_export.py +++ b/modelx/tests/export/test_export.py @@ -236,6 +236,60 @@ def test_model_path(tmp_path_factory): from ModelPath_nomx import mx_model assert mx_model.Space1.foo() == nomx_path / 'ModelPath_nomx' + finally: + sys.path.pop(0) + m.close() + + +def test_parent(tmp_path_factory): + """Test if _parent is available both in the mx and nomx model + + Code modified from: https://github.com/fumitoh/modelx/discussions/129 + """ + + m = mx.new_model() + RA = m.new_space("RA") + + # Parameterize Space RA with `calc_loop`. + # This means RA creates exact copies of itself parameterized by calc_loop on the fly, + # such as RA[0], RA[1], RA[2], etc. + # They are dynamic child spaces of RA. + RA.parameters = ("calc_loop",) + RA.calc_loop = 0 # In RA + + # Define BEL_LAPSE in RA. In the formula, calc_loop is the value given to the parameter of RA[calc_loop]. + # For example, calc_loop == 0 in RA[0].BEL_LAPSE(), calc_loop == 1 in RA[1].BEL_LAPSE(), and so on. + # In the formula, `_space` is a special name that represents the parent space of the Cells. + # For example, _space is RA[2] in RA[2].BEL_LAPSE(). _space.parent represents the parent space of RA[2], which is RA. + # So, _space.parent[1].BEL_LAPSE() means RA[1].BEL_LAPSE() + + @mx.defcells(space=RA) + def BEL_LAPSE(): + if calc_loop == 0: + return 0 + elif calc_loop == 1: + return 120 + else: + return _space._parent[1].BEL_LAPSE() + + assert RA.BEL_LAPSE() == 0 + assert RA[0].BEL_LAPSE() == 0 + + for i in range(1, 5): + RA[i].BEL_LAPSE() == 120 + + nomx_path = tmp_path_factory.mktemp('model') + m.export(nomx_path / 'Parent_nomx') + + try: + sys.path.insert(0, str(nomx_path)) + from Parent_nomx import mx_model as nomx + + assert nomx.RA.BEL_LAPSE() == 0 + assert nomx.RA[0].BEL_LAPSE() == 0 + for i in range(1, 5): + nomx.RA[i].BEL_LAPSE() == 120 + finally: sys.path.pop(0) m.close() \ No newline at end of file