From f60a2d7c4375dd034a3bef78d29b4e039b651fe0 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Wed, 11 Dec 2024 17:34:24 -0500 Subject: [PATCH 01/17] test: Add test for new datamodel API --- .../datamodel_event_streaming.py | 10 +- tests/test_datamodel_api.py | 501 ++++++++++++++++++ 2 files changed, 506 insertions(+), 5 deletions(-) create mode 100644 tests/test_datamodel_api.py diff --git a/src/ansys/fluent/core/streaming_services/datamodel_event_streaming.py b/src/ansys/fluent/core/streaming_services/datamodel_event_streaming.py index 5c0ff5e1363..1627d8870d1 100644 --- a/src/ansys/fluent/core/streaming_services/datamodel_event_streaming.py +++ b/src/ansys/fluent/core/streaming_services/datamodel_event_streaming.py @@ -66,12 +66,12 @@ def _process_streaming(self, id, stream_begin_method, started_evt, *args, **kwar elif response.HasField("commandAttributeChangedEventResponse"): value = response.commandAttributeChangedEventResponse.value cb[1](_convert_variant_to_value(value)) - elif ( - response.HasField("modifiedEventResponse") - or response.HasField("deletedEventResponse") - or response.HasField("affectedEventResponse") - ): + elif response.HasField( + "modifiedEventResponse" + ) or response.HasField("affectedEventResponse"): cb[1](cb[0]) + elif response.HasField("deletedEventResponse"): + cb[1]() elif response.HasField("commandExecutedEventResponse"): command = response.commandExecutedEventResponse.command args = _convert_variant_to_value( diff --git a/tests/test_datamodel_api.py b/tests/test_datamodel_api.py new file mode 100644 index 00000000000..71bd16ec215 --- /dev/null +++ b/tests/test_datamodel_api.py @@ -0,0 +1,501 @@ +import time + +import pytest + +from ansys.fluent.core.services.datamodel_se import ( + PyCommand, + PyDictionary, + PyMenu, + PyNamedObjectContainer, + PyTextual, + SubscribeEventError, + convert_path_to_se_path, +) +from ansys.fluent.core.utils.execution import timeout_loop + +ENV_VARS = ["REMOTING_NEW_DM_API", "REMOTING_MAPPED_NEW_DM_API"] + + +@pytest.fixture(params=["old", "new"]) +def api_version(request, monkeypatch: pytest.MonkeyPatch) -> None: + if request.param == "new": + for var in ENV_VARS: + monkeypatch.setenv(var, "1") + + +rule_str = ( + "RULES:\n" + " STRING: X\n" + " default = ijk\n" + " END\n" + " SINGLETON: ROOT\n" + " members = A, B, D, G\n" + " commands= C\n" + " SINGLETON: A\n" + " members = X\n" + " x = $./X\n" + " END\n" + " OBJECT: B\n" + " members = X\n" + " END\n" + " SINGLETON: D\n" + " members = E, F, X\n" + " SINGLETON: E\n" + " members = X\n" + " END\n" + " SINGLETON: F\n" + " members = X\n" + " END\n" + " END\n" + " SINGLETON: G\n" + " members = H\n" + " DICT: H\n" + " END\n" + " END\n" + " COMMAND: C\n" + " arguments = X\n" + " x = $/A/X\n" + " END\n" + " END\n" + "END\n" +) + + +class test_root(PyMenu): + def __init__(self, service, rules, path): + self.A = self.__class__.A(service, rules, path + [("A", "")]) + self.B = self.__class__.B(service, rules, path + [("B", "")]) + self.C = self.__class__.C(service, rules, path + [("C", "")]) + self.D = self.__class__.D(service, rules, path + [("D", "")]) + self.G = self.__class__.G(service, rules, path + [("G", "")]) + super().__init__(service, rules, path) + + class A(PyMenu): + def __init__(self, service, rules, path): + self.X = self.__class__.X(service, rules, path + [("X", "")]) + super().__init__(service, rules, path) + + class X(PyTextual): + pass + + class B(PyNamedObjectContainer): + class _B(PyMenu): + def __init__(self, service, rules, path): + self.X = self.__class__.X(service, rules, path + [("X", "")]) + super().__init__(service, rules, path) + + class X(PyTextual): + pass + + class C(PyCommand): + pass + + class D(PyMenu): + def __init__(self, service, rules, path): + self.E = self.__class__.E(service, rules, path + [("E", "")]) + self.F = self.__class__.F(service, rules, path + [("F", "")]) + self.X = self.__class__.X(service, rules, path + [("X", "")]) + super().__init__(service, rules, path) + + class E(PyMenu): + def __init__(self, service, rules, path): + self.X = self.__class__.X(service, rules, path + [("X", "")]) + super().__init__(service, rules, path) + + class X(PyTextual): + pass + + class F(PyMenu): + def __init__(self, service, rules, path): + self.X = self.__class__.X(service, rules, path + [("X", "")]) + super().__init__(service, rules, path) + + class X(PyTextual): + pass + + class X(PyTextual): + pass + + class G(PyMenu): + def __init__(self, service, rules, path): + self.H = self.__class__.H(service, rules, path + [("H", "")]) + super().__init__(service, rules, path) + + class H(PyDictionary): + pass + + +def _create_datamodel_root(session, rules_str) -> None: + rules_file_name = "test.fdl" + session.scheme_eval.scheme_eval( + f'(with-output-to-file "{rules_file_name}" (lambda () (format "~a" "{rules_str}")))' + ) + session.scheme_eval.scheme_eval( + '(state/register-new-state-engine "test" "test.fdl")' + ) + session.scheme_eval.scheme_eval(f'(remove-file "{rules_file_name}")') + assert session.scheme_eval.scheme_eval('(state/find-root "test")') > 0 + return test_root(session._se_service, "test", []) + + +@pytest.mark.fluent_version(">=25.2") +def test_env_var_setting(api_version, request, new_solver_session): + solver = new_solver_session + test_name = request.node.name + for var in ENV_VARS: + # TODO: It might be possible to check the param value in the fixture + # instead of checking the test name here. + if test_name.endswith("[old]"): + assert solver.scheme_eval.scheme_eval(f'(getenv "{var}")') is None + elif test_name.endswith("[new]"): + assert solver.scheme_eval.scheme_eval(f'(getenv "{var}")') == "1" + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_on_child_created(api_version, new_solver_session): + solver = new_solver_session + root = _create_datamodel_root(solver, rule_str) + service = solver._se_service + called = 0 + created = [] + + def cb(obj): + nonlocal called + nonlocal created + called += 1 + created.append(convert_path_to_se_path(obj.path)) + + subscription = service.add_on_child_created("test", "/", "B", root, cb) + assert called == 0 + assert created == [] + service.set_state("test", "/", {"B:b": {"_name_": "b"}}) + timeout_loop(lambda: called == 1, timeout=5) + assert called == 1 + assert created == ["/B:b"] + subscription.unsubscribe() + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_on_changed(api_version, new_solver_session): + solver = new_solver_session + root = _create_datamodel_root(solver, rule_str) + service = solver._se_service + called = 0 + state = None + called_obj = 0 + state_obj = None + + def cb(obj): + nonlocal called + nonlocal state + state = obj() + called += 1 + + def cb_obj(obj): + nonlocal called_obj + nonlocal state_obj + state_obj = obj() + called_obj += 1 + + subscription = service.add_on_changed("test", "/A/X", root.A.X, cb) + subscription_obj = service.add_on_changed("test", "/A", root.A, cb_obj) + assert called == 0 + assert state is None + assert called_obj == 0 + assert state_obj is None + service.set_state("test", "/A/X", "lmn") + timeout_loop(lambda: called == 1, timeout=5) + assert called == 1 + assert state == "lmn" + assert called_obj == 1 + assert state_obj == {"X": "lmn"} + service.set_state("test", "/A/X", "abc") + timeout_loop(lambda: called == 2, timeout=5) + assert called == 2 + assert state == "abc" + assert called_obj == 2 + assert state_obj == {"X": "abc"} + subscription.unsubscribe() + subscription_obj.unsubscribe() + service.set_state("test", "/A/X", "xyz") + time.sleep(5) + assert called == 2 + assert state == "abc" + assert called_obj == 2 + assert state_obj == {"X": "abc"} + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_on_affected(api_version, new_solver_session): + solver = new_solver_session + root = _create_datamodel_root(solver, rule_str) + service = solver._se_service + called = 0 + + def cb(obj): + nonlocal called + called += 1 + + subscription = service.add_on_affected("test", "/D", root.D, cb) + assert called == 0 + service.set_state("test", "/D/X", "lmn") + timeout_loop(lambda: called == 1, timeout=5) + assert called == 1 + service.set_state("test", "/D/E/X", "lmn") + timeout_loop(lambda: called == 2, timeout=5) + assert called == 2 + service.set_state("test", "/A/X", "lmn") + time.sleep(5) + assert called == 2 + subscription.unsubscribe() + service.set_state("test", "/D/E/X", "pqr") + time.sleep(5) + assert called == 2 + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_on_affected_at_type_path(api_version, new_solver_session): + solver = new_solver_session + root = _create_datamodel_root(solver, rule_str) + service = solver._se_service + called = 0 + + def cb(obj): + nonlocal called + called += 1 + + subscription = service.add_on_affected_at_type_path("test", "/D", "E", root.D.E, cb) + assert called == 0 + service.set_state("test", "/D/X", "lmn") + time.sleep(5) + assert called == 0 + service.set_state("test", "/D/E/X", "lmn") + timeout_loop(lambda: called == 1, timeout=5) + assert called == 1 + service.set_state("test", "/D/F/X", "lmn") + time.sleep(5) + assert called == 1 + subscription.unsubscribe() + service.set_state("test", "/D/E/X", "pqr") + time.sleep(5) + assert called == 1 + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_on_deleted(api_version, request, new_solver_session): + solver = new_solver_session + root = _create_datamodel_root(solver, rule_str) + service = solver._se_service + called = False + called_obj = False + + def cb(): + nonlocal called + called = True + + def cb_obj(): + nonlocal called_obj + called_obj = True + + service.set_state("test", "/", {"B:b": {"_name_": "b"}}) + subscription = service.add_on_deleted("test", "/B:b/X", root.B["b"].X, cb) + subscription_obj = service.add_on_deleted("test", "/B:b", root.B["b"], cb_obj) + assert not called + assert not called_obj + service.delete_object("test", "/B:b") + timeout_loop(lambda: called_obj, timeout=5) + test_name = request.node.name + # Note comment in StateEngine test testDataModelAPIOnDeleted + if test_name.endswith("[old]"): + assert called + elif test_name.endswith("[new]"): + assert not called + assert called_obj + subscription.unsubscribe() + subscription_obj.unsubscribe() + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_on_attribute_changed(api_version, new_solver_session): + solver = new_solver_session + root = _create_datamodel_root(solver, rule_str) + service = solver._se_service + called = 0 + value = None + + def cb(val): + nonlocal called + nonlocal value + value = val + called += 1 + + subscription = service.add_on_attribute_changed("test", "/A", "x", root.A, cb) + assert called == 0 + assert value is None + service.set_state("test", "/A/X", "cde") + timeout_loop(lambda: called == 1, timeout=5) + assert called == 1 + assert value == "cde" + service.set_state("test", "/A/X", "xyz") + timeout_loop(lambda: called == 2, timeout=5) + assert called == 2 + assert value == "xyz" + subscription.unsubscribe() + service.set_state("test", "/A/X", "abc") + time.sleep(5) + assert called == 2 + assert value == "xyz" + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_on_command_attribute_changed(api_version, new_solver_session): + solver = new_solver_session + root = _create_datamodel_root(solver, rule_str) + service = solver._se_service + called = 0 + value = None + + def cb(val): + nonlocal called + nonlocal value + value = val + called += 1 + + subscription = service.add_on_command_attribute_changed( + "test", "/", "C", "x", root.C, cb + ) + assert called == 0 + assert value is None + service.set_state("test", "/A/X", "cde") + timeout_loop(lambda: called == 1, timeout=5) + assert called == 1 + assert value == "cde" + service.set_state("test", "/A/X", "xyz") + timeout_loop(lambda: called == 2, timeout=5) + assert called == 2 + # TODO: value is still "cde" in both old and new API + # assert value == "xyz" + subscription.unsubscribe() + service.set_state("test", "/A/X", "abc") + time.sleep(5) + assert called == 2 + # Commented out because of the issue above + # assert value == "xyz" + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_on_command_executed(api_version, new_solver_session): + solver = new_solver_session + root = _create_datamodel_root(solver, rule_str) + service = solver._se_service + executed = 0 + command = None + arguments = None + + def cb(obj, cmd, args): + nonlocal executed + nonlocal command + nonlocal arguments + command = cmd + arguments = args + executed += 1 + + # TODO: In C++ API, we don't need to pass the command name + subscription = service.add_on_command_executed("test", "/", "C", root, cb) + assert executed == 0 + assert command is None + assert arguments is None + service.execute_command("test", "/", "C", dict(X="abc")) + timeout_loop(lambda: executed == 1, timeout=5) + assert executed == 1 + assert command == "C" + assert arguments == {"X": "abc"} + subscription.unsubscribe() + service.execute_command("test", "/", "C", dict(X="uvw")) + time.sleep(5) + assert executed == 1 + assert command == "C" + assert arguments == {"X": "abc"} + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_get_state(api_version, new_solver_session): + solver = new_solver_session + _create_datamodel_root(solver, rule_str) + service = solver._se_service + assert service.get_state("test", "/A/X") == "ijk" + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_set_state(api_version, new_solver_session): + solver = new_solver_session + _create_datamodel_root(solver, rule_str) + service = solver._se_service + service.set_state("test", "/A/X", "new_val") + assert service.get_state("test", "/A/X") == "new_val" + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_update_dict(api_version, new_solver_session): + solver = new_solver_session + _create_datamodel_root(solver, rule_str) + service = solver._se_service + service.update_dict("test", "/G/H", {"X": "abc"}) + assert service.get_state("test", "/G/H") == {"X": "abc"} + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_on_bad_input(api_version, request, new_solver_session): + solver = new_solver_session + root = _create_datamodel_root(solver, rule_str) + service = solver._se_service + test_name = request.node.name + new_api = test_name.endswith("[new]") + with pytest.raises(SubscribeEventError): + service.add_on_child_created("test", "", "", root, lambda _: None) + with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue + service.add_on_child_created("test", "/BB", "B", root, lambda _: None) + with pytest.raises(SubscribeEventError): + service.add_on_child_created("test", "/", "A", root, lambda _: None) + with pytest.raises(SubscribeEventError): + service.add_on_child_created("test", "/", "BB", root, lambda _: None) + with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue + service.add_on_changed("test", "/BB", root, lambda _: None) + with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue + service.add_on_deleted("test", "/BB", root, lambda: None) + with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue + service.add_on_affected("test", "/BB", root, lambda _: None) + with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue + service.add_on_affected_at_type_path("test", "/BB", "B", root, lambda: None) + # TODO: not raised in the old API - issue + if new_api: + with pytest.raises(SubscribeEventError): + service.add_on_affected_at_type_path("test", "/", "BB", root, lambda: None) + with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue + service.add_on_attribute_changed( + "test", "/BB", "isActive", root, lambda _: None + ) + with pytest.raises(SubscribeEventError): + service.add_on_attribute_changed("test", "/A", "", root, lambda _: None) + with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue + service.add_on_command_attribute_changed( + "test", "/BB", "C", "isActive", root, lambda _: None + ) + with pytest.raises(SubscribeEventError): + service.add_on_command_attribute_changed( + "test", "/A", "CC", "", root, lambda _: None + ) + with pytest.raises(SubscribeEventError): + service.add_on_command_attribute_changed( + "test", "/", "CC", "isActive", root, lambda _: None + ) + with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue + service.add_on_command_executed("test", "/BB", "C", root, lambda _: None) + + +@pytest.mark.fluent_version(">=25.2") +def test_datamodel_api_static_info(api_version, new_solver_session): + solver = new_solver_session + _create_datamodel_root(solver, rule_str) + service = solver._se_service + assert service.get_static_info("test") From 93ea5e7284df5b8c2e43c83a8cf23c525d5b57ed Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Wed, 11 Dec 2024 18:44:28 -0500 Subject: [PATCH 02/17] test: Adding test_mapped_api.py --- tests/conftest.py | 9 ++++ tests/test_datamodel_api.py | 84 +++++++++++++-------------------- tests/test_datamodel_service.py | 34 +++++-------- tests/test_mapped_api.py | 71 ++++++++++++++++++++++++++++ tests/util/__init__.py | 16 +++++++ 5 files changed, 140 insertions(+), 74 deletions(-) create mode 100644 tests/test_mapped_api.py create mode 100644 tests/util/__init__.py diff --git a/tests/conftest.py b/tests/conftest.py index c6edd7b3835..5eee44b7b14 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,6 +16,8 @@ from ansys.fluent.core.utils.file_transfer_service import RemoteFileTransferStrategy from ansys.fluent.core.utils.fluent_version import FluentVersion +sys.path.append(Path(__file__).parent / "util") + def pytest_addoption(parser): parser.addoption( @@ -383,3 +385,10 @@ def periodic_rot_settings_session(new_solver_session): @pytest.fixture def disable_datamodel_cache(monkeypatch: pytest.MonkeyPatch): monkeypatch.setattr(pyfluent, "DATAMODEL_USE_STATE_CACHE", False) + + +@pytest.fixture(params=["old", "new"]) +def datamodel_api_version(request, monkeypatch: pytest.MonkeyPatch) -> None: + if request.param == "new": + monkeypatch.setenv("REMOTING_NEW_DM_API", "1") + monkeypatch.setenv("REMOTING_MAPPED_NEW_DM_API", "1") diff --git a/tests/test_datamodel_api.py b/tests/test_datamodel_api.py index 71bd16ec215..dee832eaf1e 100644 --- a/tests/test_datamodel_api.py +++ b/tests/test_datamodel_api.py @@ -1,6 +1,7 @@ import time import pytest +from util import create_datamodel_root_in_server from ansys.fluent.core.services.datamodel_se import ( PyCommand, @@ -13,16 +14,6 @@ ) from ansys.fluent.core.utils.execution import timeout_loop -ENV_VARS = ["REMOTING_NEW_DM_API", "REMOTING_MAPPED_NEW_DM_API"] - - -@pytest.fixture(params=["old", "new"]) -def api_version(request, monkeypatch: pytest.MonkeyPatch) -> None: - if request.param == "new": - for var in ENV_VARS: - monkeypatch.setenv(var, "1") - - rule_str = ( "RULES:\n" " STRING: X\n" @@ -125,24 +116,11 @@ class H(PyDictionary): pass -def _create_datamodel_root(session, rules_str) -> None: - rules_file_name = "test.fdl" - session.scheme_eval.scheme_eval( - f'(with-output-to-file "{rules_file_name}" (lambda () (format "~a" "{rules_str}")))' - ) - session.scheme_eval.scheme_eval( - '(state/register-new-state-engine "test" "test.fdl")' - ) - session.scheme_eval.scheme_eval(f'(remove-file "{rules_file_name}")') - assert session.scheme_eval.scheme_eval('(state/find-root "test")') > 0 - return test_root(session._se_service, "test", []) - - @pytest.mark.fluent_version(">=25.2") -def test_env_var_setting(api_version, request, new_solver_session): +def test_env_var_setting(datamodel_api_version, request, new_solver_session): solver = new_solver_session test_name = request.node.name - for var in ENV_VARS: + for var in ["REMOTING_NEW_DM_API", "REMOTING_MAPPED_NEW_DM_API"]: # TODO: It might be possible to check the param value in the fixture # instead of checking the test name here. if test_name.endswith("[old]"): @@ -152,9 +130,9 @@ def test_env_var_setting(api_version, request, new_solver_session): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_child_created(api_version, new_solver_session): +def test_datamodel_api_on_child_created(datamodel_api_version, new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, rule_str) + root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service called = 0 created = [] @@ -176,9 +154,9 @@ def cb(obj): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_changed(api_version, new_solver_session): +def test_datamodel_api_on_changed(datamodel_api_version, new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, rule_str) + root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service called = 0 state = None @@ -226,9 +204,9 @@ def cb_obj(obj): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_affected(api_version, new_solver_session): +def test_datamodel_api_on_affected(datamodel_api_version, new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, rule_str) + root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service called = 0 @@ -254,9 +232,11 @@ def cb(obj): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_affected_at_type_path(api_version, new_solver_session): +def test_datamodel_api_on_affected_at_type_path( + datamodel_api_version, new_solver_session +): solver = new_solver_session - root = _create_datamodel_root(solver, rule_str) + root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service called = 0 @@ -282,9 +262,9 @@ def cb(obj): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_deleted(api_version, request, new_solver_session): +def test_datamodel_api_on_deleted(datamodel_api_version, request, new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, rule_str) + root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service called = False called_obj = False @@ -316,9 +296,9 @@ def cb_obj(): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_attribute_changed(api_version, new_solver_session): +def test_datamodel_api_on_attribute_changed(datamodel_api_version, new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, rule_str) + root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service called = 0 value = None @@ -348,9 +328,11 @@ def cb(val): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_command_attribute_changed(api_version, new_solver_session): +def test_datamodel_api_on_command_attribute_changed( + datamodel_api_version, new_solver_session +): solver = new_solver_session - root = _create_datamodel_root(solver, rule_str) + root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service called = 0 value = None @@ -384,9 +366,9 @@ def cb(val): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_command_executed(api_version, new_solver_session): +def test_datamodel_api_on_command_executed(datamodel_api_version, new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, rule_str) + root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service executed = 0 command = None @@ -419,35 +401,35 @@ def cb(obj, cmd, args): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_get_state(api_version, new_solver_session): +def test_datamodel_api_get_state(datamodel_api_version, new_solver_session): solver = new_solver_session - _create_datamodel_root(solver, rule_str) + create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service assert service.get_state("test", "/A/X") == "ijk" @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_set_state(api_version, new_solver_session): +def test_datamodel_api_set_state(datamodel_api_version, new_solver_session): solver = new_solver_session - _create_datamodel_root(solver, rule_str) + create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service service.set_state("test", "/A/X", "new_val") assert service.get_state("test", "/A/X") == "new_val" @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_update_dict(api_version, new_solver_session): +def test_datamodel_api_update_dict(datamodel_api_version, new_solver_session): solver = new_solver_session - _create_datamodel_root(solver, rule_str) + create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service service.update_dict("test", "/G/H", {"X": "abc"}) assert service.get_state("test", "/G/H") == {"X": "abc"} @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_bad_input(api_version, request, new_solver_session): +def test_datamodel_api_on_bad_input(datamodel_api_version, request, new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, rule_str) + root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service test_name = request.node.name new_api = test_name.endswith("[new]") @@ -494,8 +476,8 @@ def test_datamodel_api_on_bad_input(api_version, request, new_solver_session): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_static_info(api_version, new_solver_session): +def test_datamodel_api_static_info(datamodel_api_version, new_solver_session): solver = new_solver_session - _create_datamodel_root(solver, rule_str) + create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service assert service.get_static_info("test") diff --git a/tests/test_datamodel_service.py b/tests/test_datamodel_service.py index 074bc925d24..a9d76aa66de 100644 --- a/tests/test_datamodel_service.py +++ b/tests/test_datamodel_service.py @@ -3,6 +3,7 @@ from google.protobuf.json_format import MessageToDict import pytest +from util import create_datamodel_root_in_server from ansys.api.fluent.v0 import datamodel_se_pb2 from ansys.api.fluent.v0.variant_pb2 import Variant @@ -567,23 +568,10 @@ class C(PyCommand): pass -def _create_datamodel_root(session, rules_str) -> PyMenu: - rules_file_name = "test.fdl" - session.scheme_eval.scheme_eval( - f'(with-output-to-file "{rules_file_name}" (lambda () (format "~a" "{rules_str}")))' - ) - session.scheme_eval.scheme_eval( - '(state/register-new-state-engine "test" "test.fdl")' - ) - session.scheme_eval.scheme_eval(f'(remove-file "{rules_file_name}")') - assert session.scheme_eval.scheme_eval('(state/find-root "test")') > 0 - return test_root(session._se_service, "test", []) - - @pytest.mark.fluent_version(">=24.2") def test_on_child_created_lifetime(new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, test_rules) + root = create_datamodel_root_in_server(solver, test_rules, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_child_created("B", lambda _: data.append(1)) @@ -601,7 +589,7 @@ def test_on_child_created_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_deleted_lifetime(new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, test_rules) + root = create_datamodel_root_in_server(solver, test_rules, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_deleted(lambda _: data.append(1)) @@ -622,7 +610,7 @@ def test_on_deleted_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_changed_lifetime(new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, test_rules) + root = create_datamodel_root_in_server(solver, test_rules, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].X.add_on_changed(lambda _: data.append(1)) @@ -640,7 +628,7 @@ def test_on_changed_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_affected_lifetime(new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, test_rules) + root = create_datamodel_root_in_server(solver, test_rules, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_affected(lambda _: data.append(1)) @@ -658,7 +646,7 @@ def test_on_affected_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_affected_at_type_path_lifetime(new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, test_rules) + root = create_datamodel_root_in_server(solver, test_rules, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_affected_at_type_path("B", lambda _: data.append(1)) @@ -676,7 +664,7 @@ def test_on_affected_at_type_path_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_command_executed_lifetime(new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, test_rules) + root = create_datamodel_root_in_server(solver, test_rules, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_command_executed("C", lambda *args: data.append(1)) @@ -694,7 +682,7 @@ def test_on_command_executed_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_attribute_changed_lifetime(new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, test_rules) + root = create_datamodel_root_in_server(solver, test_rules, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_attribute_changed("isABC", lambda _: data.append(1)) @@ -714,7 +702,7 @@ def test_on_attribute_changed_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_command_attribute_changed_lifetime(new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, test_rules) + root = create_datamodel_root_in_server(solver, test_rules, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_command_attribute_changed( @@ -748,7 +736,7 @@ def test_on_command_attribute_changed_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_affected_lifetime_with_delete_child_objects(new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, test_rules) + root = create_datamodel_root_in_server(solver, test_rules, test_root) pyfluent.logging.enable() root.A["A1"] = {} data = [] @@ -767,7 +755,7 @@ def test_on_affected_lifetime_with_delete_child_objects(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_affected_lifetime_with_delete_all_child_objects(new_solver_session): solver = new_solver_session - root = _create_datamodel_root(solver, test_rules) + root = create_datamodel_root_in_server(solver, test_rules, test_root) pyfluent.logging.enable() root.A["A1"] = {} data = [] diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py new file mode 100644 index 00000000000..e95e1d643b1 --- /dev/null +++ b/tests/test_mapped_api.py @@ -0,0 +1,71 @@ +from util import create_datamodel_root_in_server + +rules_str = ( + "RULES:\n" + " STRING: X\n" + " allowedValues = yes, no\n" + " logicalMapping = True, False\n" + " END\n" + " STRING: Y\n" + ' allowedValues = \\"1\\", \\"2\\", \\"3\\"\n' + ' default = \\"2\\"\n' + " isNumerical = True\n" + " END\n" + " INTEGER: Z\n" + " END\n" + " SINGLETON: ROOT\n" + " members = A\n" + " commands = C, D\n" + " SINGLETON: A\n" + " members = X, Y, Z\n" + " END\n" + " COMMAND: C\n" + " arguments = X\n" + " functionName = CFunc\n" + " END\n" + " COMMAND: D\n" + " arguments = X\n" + " functionName = CFunc\n" + " APIName = dd\n" + " END\n" + " END\n" + "END\n" +) + +rules_str_caps = ( + "RULES:\n" + " STRING: X\n" + " allowedValues = Yes, No\n" + " default = No\n" + " logicalMapping = True, False\n" + " END\n" + " SINGLETON: ROOT\n" + " members = A\n" + " SINGLETON: A\n" + " members = X\n" + " END\n" + " END\n" + "END\n" +) + + +def get_static_info_value(static_info, type_path): + for p in type_path.split("/"): + static_info = static_info[p] + return static_info + + +def test_datamodel_api_bool_for_str_has_correct_type( + datamodel_api_version, new_solver_session +): + solver = new_solver_session + create_datamodel_root_in_server(solver, rules_str) + service = solver._se_service + static_info = service.get_static_info("test") + assert ( + get_static_info_value(static_info, "/singletons/A/parameters/X/type") + == "Logical" + ) + cmd_args = get_static_info_value(static_info, "/commands/C/commandinfo/args") + arg0 = cmd_args[0] + assert arg0["type"] == "Logical" diff --git a/tests/util/__init__.py b/tests/util/__init__.py new file mode 100644 index 00000000000..fc8225a73da --- /dev/null +++ b/tests/util/__init__.py @@ -0,0 +1,16 @@ +import uuid + + +def create_datamodel_root_in_server(session, rules_str, root_cls=None) -> None: + rules_file_name = f"{uuid.uuid4()}.fdl" + session.scheme_eval.scheme_eval( + f'(with-output-to-file "{rules_file_name}" (lambda () (format "~a" "{rules_str}")))', + ) + # TODO: Pass appname via argument + session.scheme_eval.scheme_eval( + f'(state/register-new-state-engine "test" "{rules_file_name}")' + ) + session.scheme_eval.scheme_eval(f'(remove-file "{rules_file_name}")') + assert session.scheme_eval.scheme_eval('(state/find-root "test")') > 0 + if root_cls: + return root_cls(session._se_service, "test", []) From 83c6f2cbd94761afc47e905a456617a542c44d7e Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Wed, 11 Dec 2024 18:52:38 -0500 Subject: [PATCH 03/17] test: Adding test_mapped_api.py --- tests/conftest.py | 8 +++++++- tests/test_datamodel_api.py | 36 ++++++++++++++++++++++-------------- tests/test_mapped_api.py | 4 ++-- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 5eee44b7b14..14180cdf200 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -388,7 +388,13 @@ def disable_datamodel_cache(monkeypatch: pytest.MonkeyPatch): @pytest.fixture(params=["old", "new"]) -def datamodel_api_version(request, monkeypatch: pytest.MonkeyPatch) -> None: +def datamodel_api_version_all(request, monkeypatch: pytest.MonkeyPatch) -> None: if request.param == "new": monkeypatch.setenv("REMOTING_NEW_DM_API", "1") monkeypatch.setenv("REMOTING_MAPPED_NEW_DM_API", "1") + + +@pytest.fixture +def datamodel_api_version_new(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setenv("REMOTING_NEW_DM_API", "1") + monkeypatch.setenv("REMOTING_MAPPED_NEW_DM_API", "1") diff --git a/tests/test_datamodel_api.py b/tests/test_datamodel_api.py index dee832eaf1e..ca0fb5457ae 100644 --- a/tests/test_datamodel_api.py +++ b/tests/test_datamodel_api.py @@ -117,7 +117,7 @@ class H(PyDictionary): @pytest.mark.fluent_version(">=25.2") -def test_env_var_setting(datamodel_api_version, request, new_solver_session): +def test_env_var_setting(datamodel_api_version_all, request, new_solver_session): solver = new_solver_session test_name = request.node.name for var in ["REMOTING_NEW_DM_API", "REMOTING_MAPPED_NEW_DM_API"]: @@ -130,7 +130,7 @@ def test_env_var_setting(datamodel_api_version, request, new_solver_session): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_child_created(datamodel_api_version, new_solver_session): +def test_datamodel_api_on_child_created(datamodel_api_version_all, new_solver_session): solver = new_solver_session root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service @@ -154,7 +154,7 @@ def cb(obj): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_changed(datamodel_api_version, new_solver_session): +def test_datamodel_api_on_changed(datamodel_api_version_all, new_solver_session): solver = new_solver_session root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service @@ -204,7 +204,7 @@ def cb_obj(obj): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_affected(datamodel_api_version, new_solver_session): +def test_datamodel_api_on_affected(datamodel_api_version_all, new_solver_session): solver = new_solver_session root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service @@ -233,7 +233,7 @@ def cb(obj): @pytest.mark.fluent_version(">=25.2") def test_datamodel_api_on_affected_at_type_path( - datamodel_api_version, new_solver_session + datamodel_api_version_all, new_solver_session ): solver = new_solver_session root = create_datamodel_root_in_server(solver, rule_str, test_root) @@ -262,7 +262,9 @@ def cb(obj): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_deleted(datamodel_api_version, request, new_solver_session): +def test_datamodel_api_on_deleted( + datamodel_api_version_all, request, new_solver_session +): solver = new_solver_session root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service @@ -296,7 +298,9 @@ def cb_obj(): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_attribute_changed(datamodel_api_version, new_solver_session): +def test_datamodel_api_on_attribute_changed( + datamodel_api_version_all, new_solver_session +): solver = new_solver_session root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service @@ -329,7 +333,7 @@ def cb(val): @pytest.mark.fluent_version(">=25.2") def test_datamodel_api_on_command_attribute_changed( - datamodel_api_version, new_solver_session + datamodel_api_version_all, new_solver_session ): solver = new_solver_session root = create_datamodel_root_in_server(solver, rule_str, test_root) @@ -366,7 +370,9 @@ def cb(val): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_command_executed(datamodel_api_version, new_solver_session): +def test_datamodel_api_on_command_executed( + datamodel_api_version_all, new_solver_session +): solver = new_solver_session root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service @@ -401,7 +407,7 @@ def cb(obj, cmd, args): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_get_state(datamodel_api_version, new_solver_session): +def test_datamodel_api_get_state(datamodel_api_version_all, new_solver_session): solver = new_solver_session create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service @@ -409,7 +415,7 @@ def test_datamodel_api_get_state(datamodel_api_version, new_solver_session): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_set_state(datamodel_api_version, new_solver_session): +def test_datamodel_api_set_state(datamodel_api_version_all, new_solver_session): solver = new_solver_session create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service @@ -418,7 +424,7 @@ def test_datamodel_api_set_state(datamodel_api_version, new_solver_session): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_update_dict(datamodel_api_version, new_solver_session): +def test_datamodel_api_update_dict(datamodel_api_version_all, new_solver_session): solver = new_solver_session create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service @@ -427,7 +433,9 @@ def test_datamodel_api_update_dict(datamodel_api_version, new_solver_session): @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_on_bad_input(datamodel_api_version, request, new_solver_session): +def test_datamodel_api_on_bad_input( + datamodel_api_version_all, request, new_solver_session +): solver = new_solver_session root = create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service @@ -476,7 +484,7 @@ def test_datamodel_api_on_bad_input(datamodel_api_version, request, new_solver_s @pytest.mark.fluent_version(">=25.2") -def test_datamodel_api_static_info(datamodel_api_version, new_solver_session): +def test_datamodel_api_static_info(datamodel_api_version_all, new_solver_session): solver = new_solver_session create_datamodel_root_in_server(solver, rule_str, test_root) service = solver._se_service diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index e95e1d643b1..517d9e93388 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -50,13 +50,13 @@ def get_static_info_value(static_info, type_path): - for p in type_path.split("/"): + for p in type_path.removeprefix("/").split("/"): static_info = static_info[p] return static_info def test_datamodel_api_bool_for_str_has_correct_type( - datamodel_api_version, new_solver_session + datamodel_api_version_new, new_solver_session ): solver = new_solver_session create_datamodel_root_in_server(solver, rules_str) From ce268082be23339448098f3a3211343bc4ee3b62 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 08:56:57 -0500 Subject: [PATCH 04/17] test: Adding test_mapped_api.py --- tests/test_datamodel_api.py | 149 ++++++++++++++++++-------------- tests/test_datamodel_service.py | 30 ++++--- tests/test_mapped_api.py | 49 ++++++++++- tests/util/__init__.py | 11 +-- 4 files changed, 157 insertions(+), 82 deletions(-) diff --git a/tests/test_datamodel_api.py b/tests/test_datamodel_api.py index ca0fb5457ae..5adb4b0dd56 100644 --- a/tests/test_datamodel_api.py +++ b/tests/test_datamodel_api.py @@ -132,7 +132,8 @@ def test_env_var_setting(datamodel_api_version_all, request, new_solver_session) @pytest.mark.fluent_version(">=25.2") def test_datamodel_api_on_child_created(datamodel_api_version_all, new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service called = 0 created = [] @@ -143,10 +144,10 @@ def cb(obj): called += 1 created.append(convert_path_to_se_path(obj.path)) - subscription = service.add_on_child_created("test", "/", "B", root, cb) + subscription = service.add_on_child_created(app_name, "/", "B", root, cb) assert called == 0 assert created == [] - service.set_state("test", "/", {"B:b": {"_name_": "b"}}) + service.set_state(app_name, "/", {"B:b": {"_name_": "b"}}) timeout_loop(lambda: called == 1, timeout=5) assert called == 1 assert created == ["/B:b"] @@ -156,7 +157,8 @@ def cb(obj): @pytest.mark.fluent_version(">=25.2") def test_datamodel_api_on_changed(datamodel_api_version_all, new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service called = 0 state = None @@ -175,19 +177,19 @@ def cb_obj(obj): state_obj = obj() called_obj += 1 - subscription = service.add_on_changed("test", "/A/X", root.A.X, cb) - subscription_obj = service.add_on_changed("test", "/A", root.A, cb_obj) + subscription = service.add_on_changed(app_name, "/A/X", root.A.X, cb) + subscription_obj = service.add_on_changed(app_name, "/A", root.A, cb_obj) assert called == 0 assert state is None assert called_obj == 0 assert state_obj is None - service.set_state("test", "/A/X", "lmn") + service.set_state(app_name, "/A/X", "lmn") timeout_loop(lambda: called == 1, timeout=5) assert called == 1 assert state == "lmn" assert called_obj == 1 assert state_obj == {"X": "lmn"} - service.set_state("test", "/A/X", "abc") + service.set_state(app_name, "/A/X", "abc") timeout_loop(lambda: called == 2, timeout=5) assert called == 2 assert state == "abc" @@ -195,7 +197,7 @@ def cb_obj(obj): assert state_obj == {"X": "abc"} subscription.unsubscribe() subscription_obj.unsubscribe() - service.set_state("test", "/A/X", "xyz") + service.set_state(app_name, "/A/X", "xyz") time.sleep(5) assert called == 2 assert state == "abc" @@ -206,7 +208,8 @@ def cb_obj(obj): @pytest.mark.fluent_version(">=25.2") def test_datamodel_api_on_affected(datamodel_api_version_all, new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service called = 0 @@ -214,19 +217,19 @@ def cb(obj): nonlocal called called += 1 - subscription = service.add_on_affected("test", "/D", root.D, cb) + subscription = service.add_on_affected(app_name, "/D", root.D, cb) assert called == 0 - service.set_state("test", "/D/X", "lmn") + service.set_state(app_name, "/D/X", "lmn") timeout_loop(lambda: called == 1, timeout=5) assert called == 1 - service.set_state("test", "/D/E/X", "lmn") + service.set_state(app_name, "/D/E/X", "lmn") timeout_loop(lambda: called == 2, timeout=5) assert called == 2 - service.set_state("test", "/A/X", "lmn") + service.set_state(app_name, "/A/X", "lmn") time.sleep(5) assert called == 2 subscription.unsubscribe() - service.set_state("test", "/D/E/X", "pqr") + service.set_state(app_name, "/D/E/X", "pqr") time.sleep(5) assert called == 2 @@ -236,7 +239,8 @@ def test_datamodel_api_on_affected_at_type_path( datamodel_api_version_all, new_solver_session ): solver = new_solver_session - root = create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service called = 0 @@ -244,19 +248,21 @@ def cb(obj): nonlocal called called += 1 - subscription = service.add_on_affected_at_type_path("test", "/D", "E", root.D.E, cb) + subscription = service.add_on_affected_at_type_path( + app_name, "/D", "E", root.D.E, cb + ) assert called == 0 - service.set_state("test", "/D/X", "lmn") + service.set_state(app_name, "/D/X", "lmn") time.sleep(5) assert called == 0 - service.set_state("test", "/D/E/X", "lmn") + service.set_state(app_name, "/D/E/X", "lmn") timeout_loop(lambda: called == 1, timeout=5) assert called == 1 - service.set_state("test", "/D/F/X", "lmn") + service.set_state(app_name, "/D/F/X", "lmn") time.sleep(5) assert called == 1 subscription.unsubscribe() - service.set_state("test", "/D/E/X", "pqr") + service.set_state(app_name, "/D/E/X", "pqr") time.sleep(5) assert called == 1 @@ -266,7 +272,8 @@ def test_datamodel_api_on_deleted( datamodel_api_version_all, request, new_solver_session ): solver = new_solver_session - root = create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service called = False called_obj = False @@ -279,12 +286,12 @@ def cb_obj(): nonlocal called_obj called_obj = True - service.set_state("test", "/", {"B:b": {"_name_": "b"}}) - subscription = service.add_on_deleted("test", "/B:b/X", root.B["b"].X, cb) - subscription_obj = service.add_on_deleted("test", "/B:b", root.B["b"], cb_obj) + service.set_state(app_name, "/", {"B:b": {"_name_": "b"}}) + subscription = service.add_on_deleted(app_name, "/B:b/X", root.B["b"].X, cb) + subscription_obj = service.add_on_deleted(app_name, "/B:b", root.B["b"], cb_obj) assert not called assert not called_obj - service.delete_object("test", "/B:b") + service.delete_object(app_name, "/B:b") timeout_loop(lambda: called_obj, timeout=5) test_name = request.node.name # Note comment in StateEngine test testDataModelAPIOnDeleted @@ -302,7 +309,8 @@ def test_datamodel_api_on_attribute_changed( datamodel_api_version_all, new_solver_session ): solver = new_solver_session - root = create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service called = 0 value = None @@ -313,19 +321,19 @@ def cb(val): value = val called += 1 - subscription = service.add_on_attribute_changed("test", "/A", "x", root.A, cb) + subscription = service.add_on_attribute_changed(app_name, "/A", "x", root.A, cb) assert called == 0 assert value is None - service.set_state("test", "/A/X", "cde") + service.set_state(app_name, "/A/X", "cde") timeout_loop(lambda: called == 1, timeout=5) assert called == 1 assert value == "cde" - service.set_state("test", "/A/X", "xyz") + service.set_state(app_name, "/A/X", "xyz") timeout_loop(lambda: called == 2, timeout=5) assert called == 2 assert value == "xyz" subscription.unsubscribe() - service.set_state("test", "/A/X", "abc") + service.set_state(app_name, "/A/X", "abc") time.sleep(5) assert called == 2 assert value == "xyz" @@ -336,7 +344,8 @@ def test_datamodel_api_on_command_attribute_changed( datamodel_api_version_all, new_solver_session ): solver = new_solver_session - root = create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service called = 0 value = None @@ -348,21 +357,21 @@ def cb(val): called += 1 subscription = service.add_on_command_attribute_changed( - "test", "/", "C", "x", root.C, cb + app_name, "/", "C", "x", root.C, cb ) assert called == 0 assert value is None - service.set_state("test", "/A/X", "cde") + service.set_state(app_name, "/A/X", "cde") timeout_loop(lambda: called == 1, timeout=5) assert called == 1 assert value == "cde" - service.set_state("test", "/A/X", "xyz") + service.set_state(app_name, "/A/X", "xyz") timeout_loop(lambda: called == 2, timeout=5) assert called == 2 # TODO: value is still "cde" in both old and new API # assert value == "xyz" subscription.unsubscribe() - service.set_state("test", "/A/X", "abc") + service.set_state(app_name, "/A/X", "abc") time.sleep(5) assert called == 2 # Commented out because of the issue above @@ -374,7 +383,8 @@ def test_datamodel_api_on_command_executed( datamodel_api_version_all, new_solver_session ): solver = new_solver_session - root = create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service executed = 0 command = None @@ -389,17 +399,17 @@ def cb(obj, cmd, args): executed += 1 # TODO: In C++ API, we don't need to pass the command name - subscription = service.add_on_command_executed("test", "/", "C", root, cb) + subscription = service.add_on_command_executed(app_name, "/", "C", root, cb) assert executed == 0 assert command is None assert arguments is None - service.execute_command("test", "/", "C", dict(X="abc")) + service.execute_command(app_name, "/", "C", dict(X="abc")) timeout_loop(lambda: executed == 1, timeout=5) assert executed == 1 assert command == "C" assert arguments == {"X": "abc"} subscription.unsubscribe() - service.execute_command("test", "/", "C", dict(X="uvw")) + service.execute_command(app_name, "/", "C", dict(X="uvw")) time.sleep(5) assert executed == 1 assert command == "C" @@ -409,27 +419,30 @@ def cb(obj, cmd, args): @pytest.mark.fluent_version(">=25.2") def test_datamodel_api_get_state(datamodel_api_version_all, new_solver_session): solver = new_solver_session - create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service - assert service.get_state("test", "/A/X") == "ijk" + assert service.get_state(app_name, "/A/X") == "ijk" @pytest.mark.fluent_version(">=25.2") def test_datamodel_api_set_state(datamodel_api_version_all, new_solver_session): solver = new_solver_session - create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service - service.set_state("test", "/A/X", "new_val") - assert service.get_state("test", "/A/X") == "new_val" + service.set_state(app_name, "/A/X", "new_val") + assert service.get_state(app_name, "/A/X") == "new_val" @pytest.mark.fluent_version(">=25.2") def test_datamodel_api_update_dict(datamodel_api_version_all, new_solver_session): solver = new_solver_session - create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service - service.update_dict("test", "/G/H", {"X": "abc"}) - assert service.get_state("test", "/G/H") == {"X": "abc"} + service.update_dict(app_name, "/G/H", {"X": "abc"}) + assert service.get_state(app_name, "/G/H") == {"X": "abc"} @pytest.mark.fluent_version(">=25.2") @@ -437,55 +450,59 @@ def test_datamodel_api_on_bad_input( datamodel_api_version_all, request, new_solver_session ): solver = new_solver_session - root = create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service test_name = request.node.name new_api = test_name.endswith("[new]") with pytest.raises(SubscribeEventError): - service.add_on_child_created("test", "", "", root, lambda _: None) + service.add_on_child_created(app_name, "", "", root, lambda _: None) with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue - service.add_on_child_created("test", "/BB", "B", root, lambda _: None) + service.add_on_child_created(app_name, "/BB", "B", root, lambda _: None) with pytest.raises(SubscribeEventError): - service.add_on_child_created("test", "/", "A", root, lambda _: None) + service.add_on_child_created(app_name, "/", "A", root, lambda _: None) with pytest.raises(SubscribeEventError): - service.add_on_child_created("test", "/", "BB", root, lambda _: None) + service.add_on_child_created(app_name, "/", "BB", root, lambda _: None) with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue - service.add_on_changed("test", "/BB", root, lambda _: None) + service.add_on_changed(app_name, "/BB", root, lambda _: None) with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue - service.add_on_deleted("test", "/BB", root, lambda: None) + service.add_on_deleted(app_name, "/BB", root, lambda: None) with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue - service.add_on_affected("test", "/BB", root, lambda _: None) + service.add_on_affected(app_name, "/BB", root, lambda _: None) with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue - service.add_on_affected_at_type_path("test", "/BB", "B", root, lambda: None) + service.add_on_affected_at_type_path(app_name, "/BB", "B", root, lambda: None) # TODO: not raised in the old API - issue if new_api: with pytest.raises(SubscribeEventError): - service.add_on_affected_at_type_path("test", "/", "BB", root, lambda: None) + service.add_on_affected_at_type_path( + app_name, "/", "BB", root, lambda: None + ) with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue service.add_on_attribute_changed( - "test", "/BB", "isActive", root, lambda _: None + app_name, "/BB", "isActive", root, lambda _: None ) with pytest.raises(SubscribeEventError): - service.add_on_attribute_changed("test", "/A", "", root, lambda _: None) + service.add_on_attribute_changed(app_name, "/A", "", root, lambda _: None) with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue service.add_on_command_attribute_changed( - "test", "/BB", "C", "isActive", root, lambda _: None + app_name, "/BB", "C", "isActive", root, lambda _: None ) with pytest.raises(SubscribeEventError): service.add_on_command_attribute_changed( - "test", "/A", "CC", "", root, lambda _: None + app_name, "/A", "CC", "", root, lambda _: None ) with pytest.raises(SubscribeEventError): service.add_on_command_attribute_changed( - "test", "/", "CC", "isActive", root, lambda _: None + app_name, "/", "CC", "isActive", root, lambda _: None ) with pytest.raises(RuntimeError if new_api else SubscribeEventError): # TODO: issue - service.add_on_command_executed("test", "/BB", "C", root, lambda _: None) + service.add_on_command_executed(app_name, "/BB", "C", root, lambda _: None) @pytest.mark.fluent_version(">=25.2") def test_datamodel_api_static_info(datamodel_api_version_all, new_solver_session): solver = new_solver_session - create_datamodel_root_in_server(solver, rule_str, test_root) + app_name = "test" + create_datamodel_root_in_server(solver, rule_str, app_name, test_root) service = solver._se_service - assert service.get_static_info("test") + assert service.get_static_info(app_name) diff --git a/tests/test_datamodel_service.py b/tests/test_datamodel_service.py index a9d76aa66de..ce0017fac3a 100644 --- a/tests/test_datamodel_service.py +++ b/tests/test_datamodel_service.py @@ -571,7 +571,8 @@ class C(PyCommand): @pytest.mark.fluent_version(">=24.2") def test_on_child_created_lifetime(new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, test_rules, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_child_created("B", lambda _: data.append(1)) @@ -589,7 +590,8 @@ def test_on_child_created_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_deleted_lifetime(new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, test_rules, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_deleted(lambda _: data.append(1)) @@ -610,7 +612,8 @@ def test_on_deleted_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_changed_lifetime(new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, test_rules, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].X.add_on_changed(lambda _: data.append(1)) @@ -628,7 +631,8 @@ def test_on_changed_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_affected_lifetime(new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, test_rules, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_affected(lambda _: data.append(1)) @@ -646,7 +650,8 @@ def test_on_affected_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_affected_at_type_path_lifetime(new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, test_rules, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_affected_at_type_path("B", lambda _: data.append(1)) @@ -664,7 +669,8 @@ def test_on_affected_at_type_path_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_command_executed_lifetime(new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, test_rules, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_command_executed("C", lambda *args: data.append(1)) @@ -682,7 +688,8 @@ def test_on_command_executed_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_attribute_changed_lifetime(new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, test_rules, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_attribute_changed("isABC", lambda _: data.append(1)) @@ -702,7 +709,8 @@ def test_on_attribute_changed_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_command_attribute_changed_lifetime(new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, test_rules, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_command_attribute_changed( @@ -736,7 +744,8 @@ def test_on_command_attribute_changed_lifetime(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_affected_lifetime_with_delete_child_objects(new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, test_rules, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) pyfluent.logging.enable() root.A["A1"] = {} data = [] @@ -755,7 +764,8 @@ def test_on_affected_lifetime_with_delete_child_objects(new_solver_session): @pytest.mark.fluent_version(">=24.2") def test_on_affected_lifetime_with_delete_all_child_objects(new_solver_session): solver = new_solver_session - root = create_datamodel_root_in_server(solver, test_rules, test_root) + app_name = "test" + root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) pyfluent.logging.enable() root.A["A1"] = {} data = [] diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index 517d9e93388..2b240577366 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -55,11 +55,24 @@ def get_static_info_value(static_info, type_path): return static_info +def get_state_from_remote_app(session, app_name, type_path): + return session.scheme_eval.scheme_eval( + f'(state/object/get-state (state/object/find-child (state/find-root "{app_name}") "{type_path}"))' + ) + + +def get_error_state_message_from_remote_app(session, app_name, type_path): + return session.scheme_eval.scheme_eval( + f'(state/object/get-error-state-message (state/object/find-child (state/find-root "{app_name}") "{type_path}"))' + ) + + def test_datamodel_api_bool_for_str_has_correct_type( datamodel_api_version_new, new_solver_session ): solver = new_solver_session - create_datamodel_root_in_server(solver, rules_str) + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) service = solver._se_service static_info = service.get_static_info("test") assert ( @@ -69,3 +82,37 @@ def test_datamodel_api_bool_for_str_has_correct_type( cmd_args = get_static_info_value(static_info, "/commands/C/commandinfo/args") arg0 = cmd_args[0] assert arg0["type"] == "Logical" + + +def test_datamodel_api_set_bool_for_str(datamodel_api_version_new, new_solver_session): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + service.set_state(app_name, "/A/X", "yes") + assert service.get_state(app_name, "/A/X") is True + assert get_state_from_remote_app(solver, app_name, "/A/X") == "yes" + + +def test_datamodel_api_set_bool_nested_for_str( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + service.set_state(app_name, "/A", {"X": True}) + assert service.get_state(app_name, "/A/X") is True + assert get_error_state_message_from_remote_app(solver, app_name, "/A/X") is None + + +def test_datamodel_api_get_set_bool_for_str_with_flexible_strs_no_errors( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str_caps, app_name) + service = solver._se_service + service.set_state(app_name, "/A/X", True) + assert service.get_state(app_name, "/A/X") is True + assert get_error_state_message_from_remote_app(solver, app_name, "/A/X") is None diff --git a/tests/util/__init__.py b/tests/util/__init__.py index fc8225a73da..d8b11dc4f28 100644 --- a/tests/util/__init__.py +++ b/tests/util/__init__.py @@ -1,16 +1,17 @@ import uuid -def create_datamodel_root_in_server(session, rules_str, root_cls=None) -> None: +def create_datamodel_root_in_server( + session, rules_str, app_name, root_cls=None +) -> None: rules_file_name = f"{uuid.uuid4()}.fdl" session.scheme_eval.scheme_eval( f'(with-output-to-file "{rules_file_name}" (lambda () (format "~a" "{rules_str}")))', ) - # TODO: Pass appname via argument session.scheme_eval.scheme_eval( - f'(state/register-new-state-engine "test" "{rules_file_name}")' + f'(state/register-new-state-engine "{app_name}" "{rules_file_name}")' ) session.scheme_eval.scheme_eval(f'(remove-file "{rules_file_name}")') - assert session.scheme_eval.scheme_eval('(state/find-root "test")') > 0 + assert session.scheme_eval.scheme_eval(f'(state/find-root "{app_name}")') > 0 if root_cls: - return root_cls(session._se_service, "test", []) + return root_cls(session._se_service, app_name, []) From 726a00c8a936e04c5e450140ba5ca17a6f5bbbc3 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 10:51:56 -0500 Subject: [PATCH 05/17] test: Adding test_mapped_api.py --- tests/test_mapped_api.py | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index 2b240577366..f595b56e72f 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -1,3 +1,4 @@ +import pytest from util import create_datamodel_root_in_server rules_str = ( @@ -116,3 +117,51 @@ def test_datamodel_api_get_set_bool_for_str_with_flexible_strs_no_errors( service.set_state(app_name, "/A/X", True) assert service.get_state(app_name, "/A/X") is True assert get_error_state_message_from_remote_app(solver, app_name, "/A/X") is None + + +def test_datamodel_api_get_attrs_bool_for_str( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str_caps, app_name) + service = solver._se_service + # assert service.get_attribute_value(app_name, "/A/Z", "allowedValues") is None # TODO: issue in accessing the object + assert service.get_attribute_value(app_name, "/A/X", "allowedValues") is None + + +def test_datamodel_api_get_and_set_int_for_str( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + service.set_state(app_name, "/A/Y", 1) + assert service.get_state(app_name, "/A/Y") == 1 + assert get_error_state_message_from_remote_app(solver, app_name, "/A/Y") is None + + +# TODO: what are the equivalent of following tests in Python? +# testPopulateMappingAttrTablePaths +# testMapAPIStateToDM +# testMapDMStateToAPI +# testMapNestedAPIStateToDM +# testUpdateStateDictWithMapping + + +def test_state_of_command_args_with_mapping( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + c_name = service.create_command_arguments(app_name, "/", "C") + with pytest.raises(RuntimeError): + service.set_state(app_name, f"/C:{c_name}/X", False) + assert service.get_state(app_name, f"/C:{c_name}") == {"X": None} + service.set_state(app_name, f"/C:{c_name}", {"X": False}) + assert service.get_state(app_name, f"/C:{c_name}") == {"X": False} + service.set_state(app_name, f"/C:{c_name}", {"X": True}) + assert service.get_state(app_name, f"/C:{c_name}") == {"X": True} From f17bfdf5afc75a81a9fff5f23706707cd70d7bcf Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 11:11:20 -0500 Subject: [PATCH 06/17] test: Adding test_mapped_api.py --- tests/test_mapped_api.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index f595b56e72f..60d121d964c 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -165,3 +165,33 @@ def test_state_of_command_args_with_mapping( assert service.get_state(app_name, f"/C:{c_name}") == {"X": False} service.set_state(app_name, f"/C:{c_name}", {"X": True}) assert service.get_state(app_name, f"/C:{c_name}") == {"X": True} + + +def register_external_function_in_remote_app(session, app_name, func_name): + session.scheme_eval.scheme_eval( + f'(state/register-external-fn "{app_name}" "{func_name}" (lambda (obj . args) (car args)) (cons "Variant" (list "ModelObject" "Variant")))' + ) + + +def test_execute_command_with_args_mapping( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + register_external_function_in_remote_app(solver, app_name, "CFunc") + result = service.execute_command(app_name, "/", "C", {"X": True}) + assert result == "yes" + + +def test_execute_command_with_args_and_path_mapping( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + register_external_function_in_remote_app(solver, app_name, "CFunc") + result = service.execute_command(app_name, "/", "dd", {"X": True}) + assert result == "yes" From d20fb0ab4bb93f61af9300f43518fd752025fb7f Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 12:20:36 -0500 Subject: [PATCH 07/17] test: Adding test_mapped_api.py --- tests/test_mapped_api.py | 172 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index 60d121d964c..22e54a8d926 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -195,3 +195,175 @@ def test_execute_command_with_args_and_path_mapping( register_external_function_in_remote_app(solver, app_name, "CFunc") result = service.execute_command(app_name, "/", "dd", {"X": True}) assert result == "yes" + + +def test_execute_query_with_args_mapping(datamodel_api_version_new, new_solver_session): + rules_str = ( + "RULES:\n" + " STRING: X\n" + " allowedValues = yes, no\n" + " logicalMapping = True, False\n" + " END\n" + " SINGLETON: ROOT\n" + " queries = Q\n" + " QUERY: Q\n" + " arguments = X\n" + " functionName = QFunc\n" + " END\n" + " END\n" + "END\n" + ) + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + register_external_function_in_remote_app(solver, app_name, "QFunc") + result = service.execute_query(app_name, "/", "Q", {"X": True}) + assert result == "yes" + + +def test_get_mapped_attr(datamodel_api_version_new, new_solver_session): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + assert service.get_attribute_value(app_name, "/A/X", "allowedValues") is None + assert service.get_attribute_value(app_name, "/A/Y", "allowedValues") is None + assert service.get_attribute_value(app_name, "/A/Y", "min") == 1 + assert service.get_attribute_value(app_name, "/A/Y", "max") == 3 + assert service.get_attribute_value(app_name, "/A/Y", "default") == 2 + + +def test_get_mapped_attr_defaults(datamodel_api_version_new, new_solver_session): + rules_str = ( + "RULES:\n" + " STRING: X\n" + " allowedValues = yes, no\n" + " default = no\n" + " logicalMapping = True, False\n" + " END\n" + " STRING: Y\n" + ' allowedValues = \\"1\\", \\"2\\", \\"3\\"\n' + ' default = \\"2\\"\n' + " isNumerical = True\n" + " END\n" + " INTEGER: Z\n" + " default = 42\n" + " END\n" + " SINGLETON: ROOT\n" + " members = A\n" + " SINGLETON: A\n" + " members = X, Y, Z\n" + " END\n" + " END\n" + "END\n" + ) + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + assert service.get_attribute_value(app_name, "/A/X", "default") is False + assert service.get_attribute_value(app_name, "/A/Y", "default") == 2 + assert service.get_attribute_value(app_name, "/A/Z", "default") == 42 + + +def test_get_mapped_enum_attr(datamodel_api_version_new, new_solver_session): + rules_str = ( + "RULES:\n" + " STRING: X\n" + " allowedValues = ijk, lmn\n" + " default = lmn\n" + " enum = green, yellow\n" + " END\n" + " SINGLETON: ROOT\n" + " members = A\n" + " SINGLETON: A\n" + " members = X\n" + " END\n" + " END\n" + "END\n" + ) + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + assert service.get_attribute_value(app_name, "/A/X", "allowedValues") == [ + "green", + "yellow", + ] + assert service.get_attribute_value(app_name, "/A/X", "default") == "yellow" + + +def test_get_mapped_dynamic_enum_attr(datamodel_api_version_new, new_solver_session): + rules_str = ( + "RULES:\n" + " LOGICAL: B\n" + " default = True\n" + " END\n" + " STRING: X\n" + ' allowedValues = IF($../B, (\\"ijk\\", \\"lmn\\"), (\\"ijk\\", \\"lmn\\", \\"opq\\"))\n' + " default = lmn\n" + ' enum = IF($../B, (\\"green\\", \\"yellow\\"), (\\"green\\", \\"yellow\\", \\"blue\\"))\n' + " END\n" + " SINGLETON: ROOT\n" + " members = A\n" + " SINGLETON: A\n" + " members = B, X\n" + " END\n" + " END\n" + "END\n" + ) + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + assert service.get_attribute_value(app_name, "/A/X", "allowedValues") == [ + "green", + "yellow", + ] + assert service.get_attribute_value(app_name, "/A/X", "default") == "yellow" + + +# TODO: Cannot query at command argument attribute level +@pytest.mark.skip +def test_get_mapped_command_attr(datamodel_api_version_new, new_solver_session): + rules_str = ( + "RULES:\n" + " STRING: X\n" + " allowedValues = yes, no\n" + " default = no\n" + " logicalMapping = True, False\n" + " END\n" + " STRING: Y\n" + ' allowedValues = \\"1\\", \\"2\\", \\"3\\"\n' + ' default = \\"2\\"\n' + " isNumerical = True\n" + " END\n" + " INTEGER: Z\n" + " default = 42\n" + " END\n" + " SINGLETON: ROOT\n" + " commands = C\n" + " COMMAND: C\n" + " arguments = X, Y, Z\n" + " END\n" + " END\n" + "END\n" + ) + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, rules_str, app_name) + service = solver._se_service + c_name = service.create_command_arguments(app_name, "/", "C") + service.get_state(app_name, f"/C:{c_name}/X") + assert ( + service.get_attribute_value(app_name, f"/C:{c_name}/X", "allowedValues") is None + ) + assert ( + service.get_attribute_value(app_name, f"/C:{c_name}/Y", "allowedValues") is None + ) + assert service.get_attribute_value(app_name, f"/C:{c_name}/Y", "min") == 1 + assert service.get_attribute_value(app_name, f"/C:{c_name}/Y", "max") == 3 + assert service.get_attribute_value(app_name, f"/C:{c_name}/X", "default") is False + assert service.get_attribute_value(app_name, f"/C:{c_name}/Y", "default") == 2 + assert service.get_attribute_value(app_name, f"/C:{c_name}/Z", "default") == 42 From aa414bad869f7c1328426e1eb9346d5ea4b8d50c Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 13:03:14 -0500 Subject: [PATCH 08/17] test: Adding test_mapped_api.py --- tests/test_datamodel_api.py | 1 + tests/test_mapped_api.py | 116 ++++++++++++++++++++++++++++++++---- 2 files changed, 107 insertions(+), 10 deletions(-) diff --git a/tests/test_datamodel_api.py b/tests/test_datamodel_api.py index 5adb4b0dd56..3444c168fe0 100644 --- a/tests/test_datamodel_api.py +++ b/tests/test_datamodel_api.py @@ -52,6 +52,7 @@ ) +# TODO: Generate the class hierarchy via codegen class test_root(PyMenu): def __init__(self, service, rules, path): self.A = self.__class__.A(service, rules, path + [("A", "")]) diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index 22e54a8d926..56770ed57c7 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -1,6 +1,16 @@ +import time + import pytest from util import create_datamodel_root_in_server +from ansys.fluent.core.services.datamodel_se import ( + PyCommand, + PyMenu, + PyNumerical, + PyTextual, +) +from ansys.fluent.core.utils.execution import timeout_loop + rules_str = ( "RULES:\n" " STRING: X\n" @@ -33,6 +43,38 @@ "END\n" ) + +# TODO: Generate the class hierarchy via codegen +class rules_cls(PyMenu): + def __init__(self, service, rules, path): + self.A = self.__class__.A(service, rules, path + [("A", "")]) + self.C = self.__class__.C(service, rules, path + [("C", "")]) + self.D = self.__class__.D(service, rules, path + [("D", "")]) + super().__init__(service, rules, path) + + class A(PyMenu): + def __init__(self, service, rules, path): + self.X = self.__class__.X(service, rules, path + [("X", "")]) + self.Y = self.__class__.Y(service, rules, path + [("Y", "")]) + self.Z = self.__class__.Z(service, rules, path + [("Z", "")]) + super().__init__(service, rules, path) + + class X(PyTextual): + pass + + class Y(PyTextual): + pass + + class Z(PyNumerical): + pass + + class C(PyCommand): + pass + + class D(PyCommand): + pass + + rules_str_caps = ( "RULES:\n" " STRING: X\n" @@ -324,8 +366,6 @@ def test_get_mapped_dynamic_enum_attr(datamodel_api_version_new, new_solver_sess assert service.get_attribute_value(app_name, "/A/X", "default") == "yellow" -# TODO: Cannot query at command argument attribute level -@pytest.mark.skip def test_get_mapped_command_attr(datamodel_api_version_new, new_solver_session): rules_str = ( "RULES:\n" @@ -355,15 +395,71 @@ def test_get_mapped_command_attr(datamodel_api_version_new, new_solver_session): create_datamodel_root_in_server(solver, rules_str, app_name) service = solver._se_service c_name = service.create_command_arguments(app_name, "/", "C") - service.get_state(app_name, f"/C:{c_name}/X") + # TODO: Attribute query at command argument level is not working assert ( - service.get_attribute_value(app_name, f"/C:{c_name}/X", "allowedValues") is None + service.get_attribute_value(app_name, f"/C:{c_name}", "X/allowedValues") is None ) assert ( - service.get_attribute_value(app_name, f"/C:{c_name}/Y", "allowedValues") is None + service.get_attribute_value(app_name, f"/C:{c_name}", "Y/allowedValues") is None ) - assert service.get_attribute_value(app_name, f"/C:{c_name}/Y", "min") == 1 - assert service.get_attribute_value(app_name, f"/C:{c_name}/Y", "max") == 3 - assert service.get_attribute_value(app_name, f"/C:{c_name}/X", "default") is False - assert service.get_attribute_value(app_name, f"/C:{c_name}/Y", "default") == 2 - assert service.get_attribute_value(app_name, f"/C:{c_name}/Z", "default") == 42 + assert service.get_attribute_value(app_name, f"/C:{c_name}", "Y/min") == 1 + assert service.get_attribute_value(app_name, f"/C:{c_name}", "Y/max") == 3 + assert service.get_attribute_value(app_name, f"/C:{c_name}", "X/default") is False + assert service.get_attribute_value(app_name, f"/C:{c_name}", "Y/default") == 2 + assert service.get_attribute_value(app_name, f"/C:{c_name}", "Z/default") == 42 + + +def test_on_changed_is_mapped(datamodel_api_version_new, new_solver_session): + solver = new_solver_session + app_name = "test" + root = create_datamodel_root_in_server(solver, rules_str, app_name, rules_cls) + service = solver._se_service + + called = 0 + state = None + called_obj = 0 + state_obj = None + + def on_changed(value): + nonlocal called + nonlocal state + state = value() + called += 1 + + def on_changed_obj(value): + nonlocal called_obj + nonlocal state_obj + state_obj = value() + called_obj += 1 + + subscription = service.add_on_changed(app_name, "/A/X", root.A.X, on_changed) + subscription_obj = service.add_on_changed(app_name, "/A", root.A, on_changed_obj) + + assert called == 0 + assert state is None + assert called_obj == 0 + assert state_obj is None + + service.set_state(app_name, "/A/X", True) + timeout_loop(lambda: called == 1, timeout=5) + assert called == 1 + assert state is True + assert called_obj == 1 + assert state_obj == {"X": True, "Y": 2, "Z": None} + + service.set_state(app_name, "/A/X", False) + timeout_loop(lambda: called == 2, timeout=5) + assert called == 2 + assert state is False + assert called_obj == 2 + assert state_obj == {"X": False, "Y": 2, "Z": None} + + subscription.unsubscribe() + subscription_obj.unsubscribe() + + service.set_state(app_name, "/A/X", True) + time.sleep(5) + assert called == 2 + assert state is False + assert called_obj == 2 + assert state_obj == {"X": False, "Y": 2, "Z": None} From 8b904d19dc99e70d411bf838d14ae52f36ac36e1 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 14:28:44 -0500 Subject: [PATCH 09/17] test: Adding test_mapped_api.py --- tests/test_mapped_api.py | 123 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index 56770ed57c7..510d57519a6 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -463,3 +463,126 @@ def on_changed_obj(value): assert state is False assert called_obj == 2 assert state_obj == {"X": False, "Y": 2, "Z": None} + + +def test_mapped_on_attribute_changed(datamodel_api_version_new, new_solver_session): + rules_str = ( + "RULES:\n" + " STRING: X\n" + " allowedValues = yes, no\n" + " default = $../Y\n" + " logicalMapping = True, False\n" + " END\n" + " STRING: Y\n" + " END\n" + " SINGLETON: ROOT\n" + " members = A\n" + " commands = C\n" + " SINGLETON: A\n" + " members = X, Y\n" + " END\n" + " COMMAND: C\n" + " arguments = X, Y\n" + " END\n" + " END\n" + "END\n" + ) + + class root_cls(PyMenu): + def __init__(self, service, rules, path): + self.A = self.__class__.A(service, rules, path + [("A", "")]) + self.C = self.__class__.C(service, rules, path + [("C", "")]) + super().__init__(service, rules, path) + + class A(PyMenu): + def __init__(self, service, rules, path): + self.X = self.__class__.X(service, rules, path + [("X", "")]) + self.Y = self.__class__.Y(service, rules, path + [("Y", "")]) + super().__init__(service, rules, path) + + class X(PyTextual): + pass + + class Y(PyTextual): + pass + + class C(PyCommand): + pass + + solver = new_solver_session + app_name = "test" + root = create_datamodel_root_in_server(solver, rules_str, app_name, root_cls) + service = solver._se_service + called = 0 + value = None + + def cb(val): + nonlocal called + nonlocal value + value = val + called += 1 + + subscription = service.add_on_attribute_changed( + app_name, "/A/X", "default", root.A.X, cb + ) + assert called == 0 + assert value is None + + service.set_state(app_name, "/A/Y", "no") + timeout_loop(lambda: called == 1, timeout=5) + assert called == 1 + assert value is False + + service.set_state(app_name, "/A/Y", "yes") + timeout_loop(lambda: called == 2, timeout=5) + assert called == 2 + assert value is True + + subscription.unsubscribe() + service.set_state(app_name, "/A/Y", "no") + time.sleep(5) + assert called == 2 + assert value is True + + +def test_datamodel_api_on_command_executed_mapped_args( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + root = create_datamodel_root_in_server(solver, rules_str, app_name, rules_cls) + service = solver._se_service + register_external_function_in_remote_app(solver, app_name, "CFunc") + executed = False + command = None + arguments = None + + def cb(obj, cmd, args): + nonlocal executed + nonlocal command + nonlocal arguments + command = cmd + arguments = args + executed = True + + subscription = service.add_on_command_executed(app_name, "/", "C", root, cb) + assert not executed + assert command is None + assert arguments is None + + service.execute_command(app_name, "/", "C", {"X": True}) + timeout_loop(lambda: executed, timeout=5) + assert executed + assert command == "C" + assert arguments == {"X": True} + + executed = False + command = None + arguments = None + + subscription.unsubscribe() + service.execute_command(app_name, "/", "C", {"X": False}) + time.sleep(5) + assert not executed + assert command is None + assert arguments is None From f4d4e9d7cc9275c7321d03b243cde84440dbbd80 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 15:07:08 -0500 Subject: [PATCH 10/17] test: Adding test_mapped_api.py --- tests/test_mapped_api.py | 157 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index 510d57519a6..28a7a8c9355 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -586,3 +586,160 @@ def cb(obj, cmd, args): assert not executed assert command is None assert arguments is None + + +api_name_rules_str = ( + "RULES:\n" + " STRING: __X\n" + " allowedValues = yes, no\n" + " logicalMapping = True, False\n" + " attr1 = 42.0\n" + " APIName = xxx\n" + " END\n" + " STRING: __Y\n" + ' allowedValues = \\"1\\", \\"2\\", \\"3\\"\n' + ' default = \\"2\\"\n' + " isNumerical = True\n" + " APIName = yyy\n" + " END\n" + " INTEGER: Z\n" + " END\n" + " SINGLETON: ROOT\n" + " members = __A, B, __E\n" + " commands = __C, D\n" + " SINGLETON: __A\n" + " members = __X\n" + " APIName = aaa\n" + " END\n" + " OBJECT: B\n" + " members = __Y, Z\n" + " END\n" + " OBJECT: __E\n" + " members = __Y\n" + " APIName = eee\n" + " END\n" + " COMMAND: __C\n" + " arguments = __X\n" + " functionName = CFunc\n" + " APIName = ccc\n" + " END\n" + " COMMAND: D\n" + " arguments = __X\n" + " functionName = CFunc\n" + " END\n" + " END\n" + "END\n" +) + + +def test_datamodel_api_with_mapped_names(datamodel_api_version_new, new_solver_session): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, api_name_rules_str, app_name) + service = solver._se_service + static_info = service.get_static_info(app_name) + assert ( + get_static_info_value(static_info, "/singletons/aaa/parameters/xxx/type") + == "Logical" + ) + assert ( + get_static_info_value(static_info, "/namedobjects/B/parameters/yyy/type") + == "Integer" + ) + assert ( + get_static_info_value(static_info, "/namedobjects/B/parameters/Z/type") + == "Integer" + ) + + command_args = [ + { + "helpstring": "", + "name": "xxx", + "type": "Logical", + } + ] + command_args = [sorted(x.items()) for x in command_args] + ccc_args = get_static_info_value( # noqa: F841 + static_info, "/commands/ccc/commandinfo/args" + ) + # TODO: helpstring is not being set + # assert command_args == [sorted(x.items()) for x in ccc_args] + d_args = get_static_info_value( # noqa: F841 + static_info, "/commands/D/commandinfo/args" + ) + # TODO: helpstring is not being returned + # assert command_args == [sorted(x.items()) for x in d_args] + + +# TODO: what are the equivalent of following tests in Python? +# testMapperMapDataModelPathToAPIPath +# testMapperMapAPIPathToDataModelPath +# testMapperMapDMValueToAPI + + +def test_datamodel_api_root_get_and_set_state_with_mapped_names( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, api_name_rules_str, app_name) + service = solver._se_service + assert service.get_state(app_name, "/") == {"aaa": {"xxx": None}} + service.set_state(app_name, "/__A/__X", "yes") + assert service.get_state(app_name, "/") == {"aaa": {"xxx": True}} + service.set_state(app_name, "/", {"aaa": {"xxx": False}}) + assert service.get_state(app_name, "/") == {"aaa": {"xxx": False}} + + +def test_datamodel_api_root_get_attrs_with_mapped_names( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, api_name_rules_str, app_name) + service = solver._se_service + assert service.get_attribute_value(app_name, "/aaa/xxx", "attr1") == 42.0 + service.set_state(app_name, "/", {"B:b": {}}) + assert service.get_attribute_value(app_name, "/B:b/yyy", "default") == 2 + + +def test_datamodel_api_cmd_args_op_with_mapped_names( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, api_name_rules_str, app_name) + service = solver._se_service + c_name = service.create_command_arguments(app_name, "/", "ccc") + x_path_str = f"/__C:{c_name}/xxx" # noqa: F841 + # TODO: issue + # service.set_state(app_name, x_path_str, True) + service.set_state(app_name, f"/__C:{c_name}", {"xxx": True}) + assert service.get_state(app_name, f"/__C:{c_name}") == {"xxx": True} + assert service.get_attribute_value(app_name, f"/__C:{c_name}", "xxx/attr1") == 42.0 + + +def test_datamodel_api_rename_with_mapped_names( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, api_name_rules_str, app_name) + service = solver._se_service + service.set_state(app_name, "/", {"B:b": {}}) + service.rename(app_name, "/B:b", "c") + service.set_state(app_name, "/", {"eee:e": {}}) + assert service.get_state(app_name, "/B:c/yyy") == 2 + service.rename(app_name, "/eee:e", "x") + assert service.get_state(app_name, "/eee:x/yyy") == 2 + + +def test_datamodel_api_delete_object_with_mapped_names( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + create_datamodel_root_in_server(solver, api_name_rules_str, app_name) + service = solver._se_service + service.set_state(app_name, "/", {"B:b": {}}) + service.delete_object(app_name, "/B:b") From 07871db2bcf198c4b27a44bd029a5bca0cf84ae5 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 15:40:02 -0500 Subject: [PATCH 11/17] test: Adding test_mapped_api.py --- tests/test_mapped_api.py | 117 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index 28a7a8c9355..49ea3fdd3ac 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -6,8 +6,10 @@ from ansys.fluent.core.services.datamodel_se import ( PyCommand, PyMenu, + PyNamedObjectContainer, PyNumerical, PyTextual, + convert_path_to_se_path, ) from ansys.fluent.core.utils.execution import timeout_loop @@ -632,6 +634,51 @@ def cb(obj, cmd, args): ) +class api_name_rules_cls(PyMenu): + def __init__(self, service, rules, path): + self.__A = self.__class__.__A(service, rules, path + [("__A", "")]) + self.B = self.__class__.B(service, rules, path + [("B", "")]) + self.__E = self.__class__.__E(service, rules, path + [("__E", "")]) + self.__C = self.__class__.__C(service, rules, path + [("__C", "")]) + self.D = self.__class__.D(service, rules, path + [("D", "")]) + super().__init__(service, rules, path) + + class __A(PyMenu): + def __init__(self, service, rules, path): + self.__X = self.__class__.__X(service, rules, path + [("__X", "")]) + super().__init__(service, rules, path) + + class __X(PyTextual): + pass + + class B(PyMenu): + def __init__(self, service, rules, path): + self.__Y = self.__class__.__Y(service, rules, path + [("__Y", "")]) + self.Z = self.__class__.Z(service, rules, path + [("Z", "")]) + super().__init__(service, rules, path) + + class __Y(PyTextual): + pass + + class Z(PyNumerical): + pass + + class __E(PyNamedObjectContainer): + class ___E(PyMenu): + def __init__(self, service, rules, path): + self.__Y = self.__class__.__Y(service, rules, path + [("__Y", "")]) + super().__init__(service, rules, path) + + class __Y(PyTextual): + pass + + class __C(PyCommand): + pass + + class D(PyCommand): + pass + + def test_datamodel_api_with_mapped_names(datamodel_api_version_new, new_solver_session): solver = new_solver_session app_name = "test" @@ -743,3 +790,73 @@ def test_datamodel_api_delete_object_with_mapped_names( service = solver._se_service service.set_state(app_name, "/", {"B:b": {}}) service.delete_object(app_name, "/B:b") + + +@pytest.mark.skip +def test_datamodel_api_on_created_on_changed_on_deleted_with_mapped_names( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + root = create_datamodel_root_in_server( + solver, api_name_rules_str, app_name, api_name_rules_cls + ) + service = solver._se_service + called_paths = [] + delete_count = 0 + changes = [] + + def create_cb(obj): + called_paths.append(convert_path_to_se_path(obj.path)) + + def delete_cb(): + nonlocal delete_count + delete_count += 1 + + def changed_cb(value): + changes.append(value()) + + service.add_on_child_created(app_name, "/", "eee", root, create_cb) + # TODO: fails at event streaming callback of on_child_created + # as the name "eee" is not available in the PyFluent side. + service.set_state(app_name, "/", {"eee:b": {}}) + service.set_state(app_name, "/", {"eee:c": {}}) + service.set_state(app_name, "/", {"B:d": {}}) + service.add_on_deleted(app_name, "/eee:b", root, delete_cb) + service.add_on_deleted(app_name, "/eee:c", root, delete_cb) + # TODO: Affected by name mangling of dunder members + service.add_on_changed(app_name, "/eee:b/yyy", root.__E["b"].__Y, changed_cb) + service.delete_object(app_name, "/eee:c") + service.set_state(app_name, "/", {"eee:b": {"yyy": 42}}) + assert called_paths == ["/eee:b", "/eee:c"] + assert delete_count == 1 + assert changes == [42] + + +@pytest.mark.skip +def test_datamodel_api_on_changed_with_mapped_names( + datamodel_api_version_new, new_solver_session +): + solver = new_solver_session + app_name = "test" + root = create_datamodel_root_in_server( + solver, api_name_rules_str, app_name, api_name_rules_cls + ) + service = solver._se_service + changes = [] + + def changed_cb(value): + changes.append(value()) + + service.set_state(app_name, "/", {"eee:b": {}}) + # TODO: Can't get this working due to name mangling of dunder members + service.add_on_changed(app_name, "/eee:b/yyy", root.__E["b"].__Y, changed_cb) + service.set_state(app_name, "/", {"eee:b": {"yyy": 42}}) + assert changes == [42] + + +# TODO: what are the equivalent of following tests in Python? +# testDataModelAPIWithNullCustomNameMapper +# testDataModelAPIWithAppendingCustomNameMapper +# testDataModelAPIWithSnakeyCustomNameMapper +# testDataModelAPIWithSnakeyCustomNameMapperAndMoreCamels From 4d6e6d8a6dc6cb3da2c40766ca3bde76866a71e0 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 16:09:10 -0500 Subject: [PATCH 12/17] test: Adding test_mapped_api.py --- tests/test_mapped_api.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index 49ea3fdd3ac..287ee5b9921 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -112,6 +112,7 @@ def get_error_state_message_from_remote_app(session, app_name, type_path): ) +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_bool_for_str_has_correct_type( datamodel_api_version_new, new_solver_session ): @@ -129,6 +130,7 @@ def test_datamodel_api_bool_for_str_has_correct_type( assert arg0["type"] == "Logical" +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_set_bool_for_str(datamodel_api_version_new, new_solver_session): solver = new_solver_session app_name = "test" @@ -139,6 +141,7 @@ def test_datamodel_api_set_bool_for_str(datamodel_api_version_new, new_solver_se assert get_state_from_remote_app(solver, app_name, "/A/X") == "yes" +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_set_bool_nested_for_str( datamodel_api_version_new, new_solver_session ): @@ -151,6 +154,7 @@ def test_datamodel_api_set_bool_nested_for_str( assert get_error_state_message_from_remote_app(solver, app_name, "/A/X") is None +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_get_set_bool_for_str_with_flexible_strs_no_errors( datamodel_api_version_new, new_solver_session ): @@ -163,6 +167,7 @@ def test_datamodel_api_get_set_bool_for_str_with_flexible_strs_no_errors( assert get_error_state_message_from_remote_app(solver, app_name, "/A/X") is None +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_get_attrs_bool_for_str( datamodel_api_version_new, new_solver_session ): @@ -174,6 +179,7 @@ def test_datamodel_api_get_attrs_bool_for_str( assert service.get_attribute_value(app_name, "/A/X", "allowedValues") is None +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_get_and_set_int_for_str( datamodel_api_version_new, new_solver_session ): @@ -194,6 +200,7 @@ def test_datamodel_api_get_and_set_int_for_str( # testUpdateStateDictWithMapping +@pytest.mark.fluent_version(">=25.2") def test_state_of_command_args_with_mapping( datamodel_api_version_new, new_solver_session ): @@ -217,6 +224,7 @@ def register_external_function_in_remote_app(session, app_name, func_name): ) +@pytest.mark.fluent_version(">=25.2") def test_execute_command_with_args_mapping( datamodel_api_version_new, new_solver_session ): @@ -229,6 +237,7 @@ def test_execute_command_with_args_mapping( assert result == "yes" +@pytest.mark.fluent_version(">=25.2") def test_execute_command_with_args_and_path_mapping( datamodel_api_version_new, new_solver_session ): @@ -241,6 +250,7 @@ def test_execute_command_with_args_and_path_mapping( assert result == "yes" +@pytest.mark.fluent_version(">=25.2") def test_execute_query_with_args_mapping(datamodel_api_version_new, new_solver_session): rules_str = ( "RULES:\n" @@ -266,6 +276,7 @@ def test_execute_query_with_args_mapping(datamodel_api_version_new, new_solver_s assert result == "yes" +@pytest.mark.fluent_version(">=25.2") def test_get_mapped_attr(datamodel_api_version_new, new_solver_session): solver = new_solver_session app_name = "test" @@ -278,6 +289,7 @@ def test_get_mapped_attr(datamodel_api_version_new, new_solver_session): assert service.get_attribute_value(app_name, "/A/Y", "default") == 2 +@pytest.mark.fluent_version(">=25.2") def test_get_mapped_attr_defaults(datamodel_api_version_new, new_solver_session): rules_str = ( "RULES:\n" @@ -311,6 +323,7 @@ def test_get_mapped_attr_defaults(datamodel_api_version_new, new_solver_session) assert service.get_attribute_value(app_name, "/A/Z", "default") == 42 +@pytest.mark.fluent_version(">=25.2") def test_get_mapped_enum_attr(datamodel_api_version_new, new_solver_session): rules_str = ( "RULES:\n" @@ -338,6 +351,7 @@ def test_get_mapped_enum_attr(datamodel_api_version_new, new_solver_session): assert service.get_attribute_value(app_name, "/A/X", "default") == "yellow" +@pytest.mark.fluent_version(">=25.2") def test_get_mapped_dynamic_enum_attr(datamodel_api_version_new, new_solver_session): rules_str = ( "RULES:\n" @@ -368,6 +382,7 @@ def test_get_mapped_dynamic_enum_attr(datamodel_api_version_new, new_solver_sess assert service.get_attribute_value(app_name, "/A/X", "default") == "yellow" +@pytest.mark.fluent_version(">=25.2") def test_get_mapped_command_attr(datamodel_api_version_new, new_solver_session): rules_str = ( "RULES:\n" @@ -411,6 +426,7 @@ def test_get_mapped_command_attr(datamodel_api_version_new, new_solver_session): assert service.get_attribute_value(app_name, f"/C:{c_name}", "Z/default") == 42 +@pytest.mark.fluent_version(">=25.2") def test_on_changed_is_mapped(datamodel_api_version_new, new_solver_session): solver = new_solver_session app_name = "test" @@ -467,6 +483,7 @@ def on_changed_obj(value): assert state_obj == {"X": False, "Y": 2, "Z": None} +@pytest.mark.fluent_version(">=25.2") def test_mapped_on_attribute_changed(datamodel_api_version_new, new_solver_session): rules_str = ( "RULES:\n" @@ -547,6 +564,7 @@ def cb(val): assert value is True +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_on_command_executed_mapped_args( datamodel_api_version_new, new_solver_session ): @@ -679,6 +697,7 @@ class D(PyCommand): pass +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_with_mapped_names(datamodel_api_version_new, new_solver_session): solver = new_solver_session app_name = "test" @@ -724,6 +743,7 @@ def test_datamodel_api_with_mapped_names(datamodel_api_version_new, new_solver_s # testMapperMapDMValueToAPI +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_root_get_and_set_state_with_mapped_names( datamodel_api_version_new, new_solver_session ): @@ -738,6 +758,7 @@ def test_datamodel_api_root_get_and_set_state_with_mapped_names( assert service.get_state(app_name, "/") == {"aaa": {"xxx": False}} +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_root_get_attrs_with_mapped_names( datamodel_api_version_new, new_solver_session ): @@ -750,6 +771,7 @@ def test_datamodel_api_root_get_attrs_with_mapped_names( assert service.get_attribute_value(app_name, "/B:b/yyy", "default") == 2 +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_cmd_args_op_with_mapped_names( datamodel_api_version_new, new_solver_session ): @@ -766,6 +788,7 @@ def test_datamodel_api_cmd_args_op_with_mapped_names( assert service.get_attribute_value(app_name, f"/__C:{c_name}", "xxx/attr1") == 42.0 +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_rename_with_mapped_names( datamodel_api_version_new, new_solver_session ): @@ -781,6 +804,7 @@ def test_datamodel_api_rename_with_mapped_names( assert service.get_state(app_name, "/eee:x/yyy") == 2 +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_delete_object_with_mapped_names( datamodel_api_version_new, new_solver_session ): @@ -793,6 +817,7 @@ def test_datamodel_api_delete_object_with_mapped_names( @pytest.mark.skip +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_on_created_on_changed_on_deleted_with_mapped_names( datamodel_api_version_new, new_solver_session ): @@ -834,6 +859,7 @@ def changed_cb(value): @pytest.mark.skip +@pytest.mark.fluent_version(">=25.2") def test_datamodel_api_on_changed_with_mapped_names( datamodel_api_version_new, new_solver_session ): From 2d82a0f01b19b87f1cb35b7a24b2ee752b1e0f93 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 16:46:55 -0500 Subject: [PATCH 13/17] test: use datamodelgen --- tests/test_datamodel_api.py | 7 +++++-- tests/util/__init__.py | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/tests/test_datamodel_api.py b/tests/test_datamodel_api.py index 3444c168fe0..7072df07460 100644 --- a/tests/test_datamodel_api.py +++ b/tests/test_datamodel_api.py @@ -1,7 +1,7 @@ import time import pytest -from util import create_datamodel_root_in_server +from util import create_datamodel_root_in_server, create_root_cls_using_datamodelgen from ansys.fluent.core.services.datamodel_se import ( PyCommand, @@ -134,8 +134,11 @@ def test_env_var_setting(datamodel_api_version_all, request, new_solver_session) def test_datamodel_api_on_child_created(datamodel_api_version_all, new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service + static_info = service.get_static_info(app_name) + root = create_root_cls_using_datamodelgen(static_info)(service, app_name, []) + called = 0 created = [] diff --git a/tests/util/__init__.py b/tests/util/__init__.py index d8b11dc4f28..10cd2b31a20 100644 --- a/tests/util/__init__.py +++ b/tests/util/__init__.py @@ -1,5 +1,13 @@ +from pathlib import Path +from tempfile import TemporaryDirectory import uuid +from pytest import MonkeyPatch + +import ansys.fluent.core as pyfluent +from ansys.fluent.core.codegen import StaticInfoType, datamodelgen +from ansys.fluent.core.utils import load_module + def create_datamodel_root_in_server( session, rules_str, app_name, root_cls=None @@ -15,3 +23,17 @@ def create_datamodel_root_in_server( assert session.scheme_eval.scheme_eval(f'(state/find-root "{app_name}")') > 0 if root_cls: return root_cls(session._se_service, app_name, []) + + +def create_root_cls_using_datamodelgen(static_info): + version = "252" + with TemporaryDirectory() as temp_dir: + with MonkeyPatch.context() as m: + m.setattr(pyfluent, "CODEGEN_OUTDIR", Path(temp_dir)) + # TODO: Refactor datamdodelgen so we don't need to hardcode StaticInfoType + datamodelgen.generate( + version, static_infos={StaticInfoType.DATAMODEL_WORKFLOW: static_info} + ) + gen_file = Path(temp_dir) / f"datamodel_{version}" / "workflow.py" + module = load_module("datamodel", gen_file) + return module.Root From 4aba979f082159d9f637379d42bb217071e96f99 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 17:08:54 -0500 Subject: [PATCH 14/17] test: use datamodelgen --- tests/test_datamodel_api.py | 107 ++++++-------------------- tests/test_datamodel_service.py | 60 ++++++--------- tests/test_mapped_api.py | 129 ++++---------------------------- tests/util/__init__.py | 11 +-- 4 files changed, 60 insertions(+), 247 deletions(-) diff --git a/tests/test_datamodel_api.py b/tests/test_datamodel_api.py index 7072df07460..83be2a129e4 100644 --- a/tests/test_datamodel_api.py +++ b/tests/test_datamodel_api.py @@ -1,14 +1,9 @@ import time import pytest -from util import create_datamodel_root_in_server, create_root_cls_using_datamodelgen +from util import create_datamodel_root_in_server, create_root_using_datamodelgen from ansys.fluent.core.services.datamodel_se import ( - PyCommand, - PyDictionary, - PyMenu, - PyNamedObjectContainer, - PyTextual, SubscribeEventError, convert_path_to_se_path, ) @@ -52,71 +47,6 @@ ) -# TODO: Generate the class hierarchy via codegen -class test_root(PyMenu): - def __init__(self, service, rules, path): - self.A = self.__class__.A(service, rules, path + [("A", "")]) - self.B = self.__class__.B(service, rules, path + [("B", "")]) - self.C = self.__class__.C(service, rules, path + [("C", "")]) - self.D = self.__class__.D(service, rules, path + [("D", "")]) - self.G = self.__class__.G(service, rules, path + [("G", "")]) - super().__init__(service, rules, path) - - class A(PyMenu): - def __init__(self, service, rules, path): - self.X = self.__class__.X(service, rules, path + [("X", "")]) - super().__init__(service, rules, path) - - class X(PyTextual): - pass - - class B(PyNamedObjectContainer): - class _B(PyMenu): - def __init__(self, service, rules, path): - self.X = self.__class__.X(service, rules, path + [("X", "")]) - super().__init__(service, rules, path) - - class X(PyTextual): - pass - - class C(PyCommand): - pass - - class D(PyMenu): - def __init__(self, service, rules, path): - self.E = self.__class__.E(service, rules, path + [("E", "")]) - self.F = self.__class__.F(service, rules, path + [("F", "")]) - self.X = self.__class__.X(service, rules, path + [("X", "")]) - super().__init__(service, rules, path) - - class E(PyMenu): - def __init__(self, service, rules, path): - self.X = self.__class__.X(service, rules, path + [("X", "")]) - super().__init__(service, rules, path) - - class X(PyTextual): - pass - - class F(PyMenu): - def __init__(self, service, rules, path): - self.X = self.__class__.X(service, rules, path + [("X", "")]) - super().__init__(service, rules, path) - - class X(PyTextual): - pass - - class X(PyTextual): - pass - - class G(PyMenu): - def __init__(self, service, rules, path): - self.H = self.__class__.H(service, rules, path + [("H", "")]) - super().__init__(service, rules, path) - - class H(PyDictionary): - pass - - @pytest.mark.fluent_version(">=25.2") def test_env_var_setting(datamodel_api_version_all, request, new_solver_session): solver = new_solver_session @@ -136,8 +66,7 @@ def test_datamodel_api_on_child_created(datamodel_api_version_all, new_solver_se app_name = "test" create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service - static_info = service.get_static_info(app_name) - root = create_root_cls_using_datamodelgen(static_info)(service, app_name, []) + root = create_root_using_datamodelgen(service, app_name) called = 0 created = [] @@ -162,8 +91,9 @@ def cb(obj): def test_datamodel_api_on_changed(datamodel_api_version_all, new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) called = 0 state = None called_obj = 0 @@ -213,8 +143,9 @@ def cb_obj(obj): def test_datamodel_api_on_affected(datamodel_api_version_all, new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) called = 0 def cb(obj): @@ -244,8 +175,9 @@ def test_datamodel_api_on_affected_at_type_path( ): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) called = 0 def cb(obj): @@ -277,8 +209,9 @@ def test_datamodel_api_on_deleted( ): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) called = False called_obj = False @@ -314,8 +247,9 @@ def test_datamodel_api_on_attribute_changed( ): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) called = 0 value = None @@ -349,8 +283,9 @@ def test_datamodel_api_on_command_attribute_changed( ): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) called = 0 value = None @@ -388,8 +323,9 @@ def test_datamodel_api_on_command_executed( ): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) executed = 0 command = None arguments = None @@ -424,7 +360,7 @@ def cb(obj, cmd, args): def test_datamodel_api_get_state(datamodel_api_version_all, new_solver_session): solver = new_solver_session app_name = "test" - create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service assert service.get_state(app_name, "/A/X") == "ijk" @@ -433,7 +369,7 @@ def test_datamodel_api_get_state(datamodel_api_version_all, new_solver_session): def test_datamodel_api_set_state(datamodel_api_version_all, new_solver_session): solver = new_solver_session app_name = "test" - create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service service.set_state(app_name, "/A/X", "new_val") assert service.get_state(app_name, "/A/X") == "new_val" @@ -443,7 +379,7 @@ def test_datamodel_api_set_state(datamodel_api_version_all, new_solver_session): def test_datamodel_api_update_dict(datamodel_api_version_all, new_solver_session): solver = new_solver_session app_name = "test" - create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service service.update_dict(app_name, "/G/H", {"X": "abc"}) assert service.get_state(app_name, "/G/H") == {"X": "abc"} @@ -455,8 +391,9 @@ def test_datamodel_api_on_bad_input( ): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) test_name = request.node.name new_api = test_name.endswith("[new]") with pytest.raises(SubscribeEventError): @@ -507,6 +444,6 @@ def test_datamodel_api_on_bad_input( def test_datamodel_api_static_info(datamodel_api_version_all, new_solver_session): solver = new_solver_session app_name = "test" - create_datamodel_root_in_server(solver, rule_str, app_name, test_root) + create_datamodel_root_in_server(solver, rule_str, app_name) service = solver._se_service assert service.get_static_info(app_name) diff --git a/tests/test_datamodel_service.py b/tests/test_datamodel_service.py index ce0017fac3a..c415383e3d5 100644 --- a/tests/test_datamodel_service.py +++ b/tests/test_datamodel_service.py @@ -3,18 +3,14 @@ from google.protobuf.json_format import MessageToDict import pytest -from util import create_datamodel_root_in_server +from util import create_datamodel_root_in_server, create_root_using_datamodelgen from ansys.api.fluent.v0 import datamodel_se_pb2 from ansys.api.fluent.v0.variant_pb2 import Variant import ansys.fluent.core as pyfluent from ansys.fluent.core import examples from ansys.fluent.core.services.datamodel_se import ( - PyCommand, - PyMenu, PyMenuGeneric, - PyNamedObjectContainer, - PyTextual, ReadOnlyObjectError, _convert_value_to_variant, _convert_variant_to_value, @@ -544,35 +540,12 @@ def test_read_only_set_state(new_meshing_session): ) -class test_root(PyMenu): - def __init__(self, service, rules, path): - self.A = self.__class__.A(service, rules, path + [("A", "")]) - super().__init__(service, rules, path) - - class A(PyNamedObjectContainer): - class _A(PyMenu): - def __init__(self, service, rules, path): - self.B = self.__class__.B(service, rules, path + [("B", "")]) - self.X = self.__class__.X(service, rules, path + [("X", "")]) - self.C = self.__class__.C(service, rules, "C", path) - super().__init__(service, rules, path) - - class B(PyNamedObjectContainer): - class _B(PyMenu): - pass - - class X(PyTextual): - pass - - class C(PyCommand): - pass - - @pytest.mark.fluent_version(">=24.2") def test_on_child_created_lifetime(new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) + create_datamodel_root_in_server(solver, test_rules, app_name) + root = create_root_using_datamodelgen(solver._se_service, app_name) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_child_created("B", lambda _: data.append(1)) @@ -591,7 +564,8 @@ def test_on_child_created_lifetime(new_solver_session): def test_on_deleted_lifetime(new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) + create_datamodel_root_in_server(solver, test_rules, app_name) + root = create_root_using_datamodelgen(solver._se_service, app_name) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_deleted(lambda _: data.append(1)) @@ -613,7 +587,8 @@ def test_on_deleted_lifetime(new_solver_session): def test_on_changed_lifetime(new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) + create_datamodel_root_in_server(solver, test_rules, app_name) + root = create_root_using_datamodelgen(solver._se_service, app_name) root.A["A1"] = {} data = [] _ = root.A["A1"].X.add_on_changed(lambda _: data.append(1)) @@ -632,7 +607,8 @@ def test_on_changed_lifetime(new_solver_session): def test_on_affected_lifetime(new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) + create_datamodel_root_in_server(solver, test_rules, app_name) + root = create_root_using_datamodelgen(solver._se_service, app_name) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_affected(lambda _: data.append(1)) @@ -651,7 +627,8 @@ def test_on_affected_lifetime(new_solver_session): def test_on_affected_at_type_path_lifetime(new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) + create_datamodel_root_in_server(solver, test_rules, app_name) + root = create_root_using_datamodelgen(solver._se_service, app_name) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_affected_at_type_path("B", lambda _: data.append(1)) @@ -670,7 +647,8 @@ def test_on_affected_at_type_path_lifetime(new_solver_session): def test_on_command_executed_lifetime(new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) + create_datamodel_root_in_server(solver, test_rules, app_name) + root = create_root_using_datamodelgen(solver._se_service, app_name) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_command_executed("C", lambda *args: data.append(1)) @@ -689,7 +667,8 @@ def test_on_command_executed_lifetime(new_solver_session): def test_on_attribute_changed_lifetime(new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) + create_datamodel_root_in_server(solver, test_rules, app_name) + root = create_root_using_datamodelgen(solver._se_service, app_name) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_attribute_changed("isABC", lambda _: data.append(1)) @@ -710,7 +689,8 @@ def test_on_attribute_changed_lifetime(new_solver_session): def test_on_command_attribute_changed_lifetime(new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) + create_datamodel_root_in_server(solver, test_rules, app_name) + root = create_root_using_datamodelgen(solver._se_service, app_name) root.A["A1"] = {} data = [] _ = root.A["A1"].add_on_command_attribute_changed( @@ -745,7 +725,8 @@ def test_on_command_attribute_changed_lifetime(new_solver_session): def test_on_affected_lifetime_with_delete_child_objects(new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) + create_datamodel_root_in_server(solver, test_rules, app_name) + root = create_root_using_datamodelgen(solver._se_service, app_name) pyfluent.logging.enable() root.A["A1"] = {} data = [] @@ -765,7 +746,8 @@ def test_on_affected_lifetime_with_delete_child_objects(new_solver_session): def test_on_affected_lifetime_with_delete_all_child_objects(new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, test_rules, app_name, test_root) + create_datamodel_root_in_server(solver, test_rules, app_name) + root = create_root_using_datamodelgen(solver._se_service, app_name) pyfluent.logging.enable() root.A["A1"] = {} data = [] diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index 287ee5b9921..122b08810d1 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -1,16 +1,9 @@ import time import pytest -from util import create_datamodel_root_in_server - -from ansys.fluent.core.services.datamodel_se import ( - PyCommand, - PyMenu, - PyNamedObjectContainer, - PyNumerical, - PyTextual, - convert_path_to_se_path, -) +from util import create_datamodel_root_in_server, create_root_using_datamodelgen + +from ansys.fluent.core.services.datamodel_se import convert_path_to_se_path from ansys.fluent.core.utils.execution import timeout_loop rules_str = ( @@ -46,37 +39,6 @@ ) -# TODO: Generate the class hierarchy via codegen -class rules_cls(PyMenu): - def __init__(self, service, rules, path): - self.A = self.__class__.A(service, rules, path + [("A", "")]) - self.C = self.__class__.C(service, rules, path + [("C", "")]) - self.D = self.__class__.D(service, rules, path + [("D", "")]) - super().__init__(service, rules, path) - - class A(PyMenu): - def __init__(self, service, rules, path): - self.X = self.__class__.X(service, rules, path + [("X", "")]) - self.Y = self.__class__.Y(service, rules, path + [("Y", "")]) - self.Z = self.__class__.Z(service, rules, path + [("Z", "")]) - super().__init__(service, rules, path) - - class X(PyTextual): - pass - - class Y(PyTextual): - pass - - class Z(PyNumerical): - pass - - class C(PyCommand): - pass - - class D(PyCommand): - pass - - rules_str_caps = ( "RULES:\n" " STRING: X\n" @@ -430,8 +392,9 @@ def test_get_mapped_command_attr(datamodel_api_version_new, new_solver_session): def test_on_changed_is_mapped(datamodel_api_version_new, new_solver_session): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rules_str, app_name, rules_cls) + create_datamodel_root_in_server(solver, rules_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) called = 0 state = None @@ -507,31 +470,11 @@ def test_mapped_on_attribute_changed(datamodel_api_version_new, new_solver_sessi "END\n" ) - class root_cls(PyMenu): - def __init__(self, service, rules, path): - self.A = self.__class__.A(service, rules, path + [("A", "")]) - self.C = self.__class__.C(service, rules, path + [("C", "")]) - super().__init__(service, rules, path) - - class A(PyMenu): - def __init__(self, service, rules, path): - self.X = self.__class__.X(service, rules, path + [("X", "")]) - self.Y = self.__class__.Y(service, rules, path + [("Y", "")]) - super().__init__(service, rules, path) - - class X(PyTextual): - pass - - class Y(PyTextual): - pass - - class C(PyCommand): - pass - solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rules_str, app_name, root_cls) + create_datamodel_root_in_server(solver, rules_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) called = 0 value = None @@ -570,8 +513,9 @@ def test_datamodel_api_on_command_executed_mapped_args( ): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server(solver, rules_str, app_name, rules_cls) + create_datamodel_root_in_server(solver, rules_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) register_external_function_in_remote_app(solver, app_name, "CFunc") executed = False command = None @@ -652,51 +596,6 @@ def cb(obj, cmd, args): ) -class api_name_rules_cls(PyMenu): - def __init__(self, service, rules, path): - self.__A = self.__class__.__A(service, rules, path + [("__A", "")]) - self.B = self.__class__.B(service, rules, path + [("B", "")]) - self.__E = self.__class__.__E(service, rules, path + [("__E", "")]) - self.__C = self.__class__.__C(service, rules, path + [("__C", "")]) - self.D = self.__class__.D(service, rules, path + [("D", "")]) - super().__init__(service, rules, path) - - class __A(PyMenu): - def __init__(self, service, rules, path): - self.__X = self.__class__.__X(service, rules, path + [("__X", "")]) - super().__init__(service, rules, path) - - class __X(PyTextual): - pass - - class B(PyMenu): - def __init__(self, service, rules, path): - self.__Y = self.__class__.__Y(service, rules, path + [("__Y", "")]) - self.Z = self.__class__.Z(service, rules, path + [("Z", "")]) - super().__init__(service, rules, path) - - class __Y(PyTextual): - pass - - class Z(PyNumerical): - pass - - class __E(PyNamedObjectContainer): - class ___E(PyMenu): - def __init__(self, service, rules, path): - self.__Y = self.__class__.__Y(service, rules, path + [("__Y", "")]) - super().__init__(service, rules, path) - - class __Y(PyTextual): - pass - - class __C(PyCommand): - pass - - class D(PyCommand): - pass - - @pytest.mark.fluent_version(">=25.2") def test_datamodel_api_with_mapped_names(datamodel_api_version_new, new_solver_session): solver = new_solver_session @@ -823,10 +722,9 @@ def test_datamodel_api_on_created_on_changed_on_deleted_with_mapped_names( ): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server( - solver, api_name_rules_str, app_name, api_name_rules_cls - ) + create_datamodel_root_in_server(solver, api_name_rules_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) called_paths = [] delete_count = 0 changes = [] @@ -865,10 +763,9 @@ def test_datamodel_api_on_changed_with_mapped_names( ): solver = new_solver_session app_name = "test" - root = create_datamodel_root_in_server( - solver, api_name_rules_str, app_name, api_name_rules_cls - ) + create_datamodel_root_in_server(solver, api_name_rules_str, app_name) service = solver._se_service + root = create_root_using_datamodelgen(service, app_name) changes = [] def changed_cb(value): diff --git a/tests/util/__init__.py b/tests/util/__init__.py index 10cd2b31a20..2be1c68ced9 100644 --- a/tests/util/__init__.py +++ b/tests/util/__init__.py @@ -9,9 +9,7 @@ from ansys.fluent.core.utils import load_module -def create_datamodel_root_in_server( - session, rules_str, app_name, root_cls=None -) -> None: +def create_datamodel_root_in_server(session, rules_str, app_name) -> None: rules_file_name = f"{uuid.uuid4()}.fdl" session.scheme_eval.scheme_eval( f'(with-output-to-file "{rules_file_name}" (lambda () (format "~a" "{rules_str}")))', @@ -21,12 +19,11 @@ def create_datamodel_root_in_server( ) session.scheme_eval.scheme_eval(f'(remove-file "{rules_file_name}")') assert session.scheme_eval.scheme_eval(f'(state/find-root "{app_name}")') > 0 - if root_cls: - return root_cls(session._se_service, app_name, []) -def create_root_cls_using_datamodelgen(static_info): +def create_root_using_datamodelgen(service, app_name): version = "252" + static_info = service.get_static_info(app_name) with TemporaryDirectory() as temp_dir: with MonkeyPatch.context() as m: m.setattr(pyfluent, "CODEGEN_OUTDIR", Path(temp_dir)) @@ -36,4 +33,4 @@ def create_root_cls_using_datamodelgen(static_info): ) gen_file = Path(temp_dir) / f"datamodel_{version}" / "workflow.py" module = load_module("datamodel", gen_file) - return module.Root + return module.Root(service, app_name, []) From 2964a98aa2aa7a1c1fa54557b9a6b4476b1fc33f Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 17:16:33 -0500 Subject: [PATCH 15/17] test: use datamodelgen --- tests/test_datamodel_service.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_datamodel_service.py b/tests/test_datamodel_service.py index c415383e3d5..289c5bc8a0e 100644 --- a/tests/test_datamodel_service.py +++ b/tests/test_datamodel_service.py @@ -122,7 +122,7 @@ def test_add_on_deleted(new_meshing_session): meshing.workflow.InitializeWorkflow(WorkflowType="Watertight Geometry") data = [] _ = meshing.workflow.TaskObject["Import Geometry"].add_on_deleted( - lambda obj: data.append(convert_path_to_se_path(obj.path)) + lambda: data.append(True) ) assert data == [] meshing.workflow.InitializeWorkflow(WorkflowType="Fault-tolerant Meshing") @@ -568,8 +568,8 @@ def test_on_deleted_lifetime(new_solver_session): root = create_root_using_datamodelgen(solver._se_service, app_name) root.A["A1"] = {} data = [] - _ = root.A["A1"].add_on_deleted(lambda _: data.append(1)) - root.A["A1"].add_on_deleted(lambda _: data.append(2)) + _ = root.A["A1"].add_on_deleted(lambda: data.append(1)) + root.A["A1"].add_on_deleted(lambda: data.append(2)) gc.collect() assert "/test/deleted/A:A1" in solver._se_service.subscriptions assert "/test/deleted/A:A1-1" in solver._se_service.subscriptions From a143501fee8ccbbb155801117353a94ed3e5a9e0 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 17:28:55 -0500 Subject: [PATCH 16/17] fix: test --- tests/test_mapped_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_mapped_api.py b/tests/test_mapped_api.py index 122b08810d1..6132bcc33f0 100644 --- a/tests/test_mapped_api.py +++ b/tests/test_mapped_api.py @@ -135,9 +135,9 @@ def test_datamodel_api_get_attrs_bool_for_str( ): solver = new_solver_session app_name = "test" - create_datamodel_root_in_server(solver, rules_str_caps, app_name) + create_datamodel_root_in_server(solver, rules_str, app_name) service = solver._se_service - # assert service.get_attribute_value(app_name, "/A/Z", "allowedValues") is None # TODO: issue in accessing the object + assert service.get_attribute_value(app_name, "/A/Z", "allowedValues") is None assert service.get_attribute_value(app_name, "/A/X", "allowedValues") is None From 434c42e94d912f7ad01b6e3bd619aa26e3723110 Mon Sep 17 00:00:00 2001 From: Mainak Kundu Date: Thu, 12 Dec 2024 18:33:26 -0500 Subject: [PATCH 17/17] fix: test --- src/ansys/fluent/core/services/datamodel_se.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/fluent/core/services/datamodel_se.py b/src/ansys/fluent/core/services/datamodel_se.py index 6b1520ed80a..1c6a5404762 100644 --- a/src/ansys/fluent/core/services/datamodel_se.py +++ b/src/ansys/fluent/core/services/datamodel_se.py @@ -1577,7 +1577,7 @@ def _del_item(self, key: str) -> None: # On-deleted subscription objects are unsubscribed after the datamodel # object is deleted. self[key].add_on_deleted( - lambda _: self.service.subscriptions.unsubscribe_while_deleting( + lambda: self.service.subscriptions.unsubscribe_while_deleting( self.rules, se_path, "after" ) )