From 4a625ac5239c066cdd065498255b53a7fd49ad65 Mon Sep 17 00:00:00 2001 From: dinhlongnguyen Date: Wed, 22 Jun 2022 22:54:44 +0700 Subject: [PATCH] Additional page scopes fixes (#304) (#305) * all holders are now being refreshed * fix reload page * add test * enable full test * change assert * update typo --- taipy/gui/utils/_evaluator.py | 37 ++++---- .../with_action/test_slider_input_reload.py | 95 +++++++++++++++++++ tests/taipy/gui/helpers.py | 17 +++- tests/taipy/gui/notebook/simple_gui.ipynb | 4 +- 4 files changed, 130 insertions(+), 23 deletions(-) create mode 100644 tests/taipy/gui/e2e/with_action/test_slider_input_reload.py diff --git a/taipy/gui/utils/_evaluator.py b/taipy/gui/utils/_evaluator.py index 0cd313cbc..248ec2c7c 100644 --- a/taipy/gui/utils/_evaluator.py +++ b/taipy/gui/utils/_evaluator.py @@ -112,9 +112,8 @@ def __save_expression( var_map: t.Dict[str, str], ): if expr in self.__expr_to_hash: - if expr_hash is None: - expr_hash = self.__expr_to_hash[expr] - gui._bind_var_val(expr_hash, expr_evaluated) + expr_hash = self.__expr_to_hash[expr] + gui._bind_var_val(expr_hash, expr_evaluated) return expr_hash if expr_hash is None: expr_hash = _get_expr_var_name(expr) @@ -247,28 +246,26 @@ def re_evaluate_expr(self, gui: Gui, var_name: str) -> t.Set[str]: return modified_vars # refresh expressions and holders for expr in self.__var_to_expr_list[var_name]: - if expr == expr_original or expr.startswith("_Taipy"): - continue expr_decoded, _ = _variable_decode(expr) hash_expr = self.__expr_to_hash.get(expr, "UnknownExpr") - if expr != var_name: + if expr != var_name and not expr.startswith("_Taipy"): expr_var_map = self.__expr_to_var_map.get(expr) # ["x", "y"] if expr_var_map is None: - warnings.warn(f"Someting is amiss with expression list for {expr}") - continue - eval_dict = {k: _getscopeattr_drill(gui, v) for k, v in expr_var_map.items()} - if self._is_expression(expr_decoded): - expr_string = 'f"' + expr.replace('"', '\\"') + '"' + warnings.warn(f"Something is amiss with expression list for {expr}") else: - expr_string = expr_decoded - try: - ctx: t.Dict[str, t.Any] = {} - ctx.update(self.__global_ctx) - ctx.update(eval_dict) - expr_evaluated = eval(expr_string, ctx) - _setscopeattr(gui, hash_expr, expr_evaluated) - except Exception as e: - warnings.warn(f"Problem evaluating {expr_string}: {e}") + eval_dict = {k: _getscopeattr_drill(gui, v) for k, v in expr_var_map.items()} + if self._is_expression(expr_decoded): + expr_string = 'f"' + _variable_decode(expr)[0].replace('"', '\\"') + '"' + else: + expr_string = expr_decoded + try: + ctx: t.Dict[str, t.Any] = {} + ctx.update(self.__global_ctx) + ctx.update(eval_dict) + expr_evaluated = eval(expr_string, ctx) + _setscopeattr(gui, hash_expr, expr_evaluated) + except Exception as e: + warnings.warn(f"Problem evaluating {expr_string}: {e}") # refresh holders if any for h in self.__expr_to_holders.get(expr, []): holder_hash = self.__get_holder_hash(h, self.get_hash_from_expr(expr)) diff --git a/tests/taipy/gui/e2e/with_action/test_slider_input_reload.py b/tests/taipy/gui/e2e/with_action/test_slider_input_reload.py new file mode 100644 index 000000000..023f6ddcf --- /dev/null +++ b/tests/taipy/gui/e2e/with_action/test_slider_input_reload.py @@ -0,0 +1,95 @@ +# Copyright 2022 Avaiga Private Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +import inspect +import logging +from importlib import util + +import pytest + +if util.find_spec("playwright"): + from playwright._impl._page import Page + +from taipy.gui import Gui + + +def edit_and_assert_page(page: "Page"): + assert_input(page, "0") + + page.fill("#input2 input", "20") + function_evaluated = True + try: + page.wait_for_function("document.querySelector('#val1').innerText !== '0'") + except Exception as e: + function_evaluated = False + logging.getLogger().debug(f"Function evaluation timeout.\n{e}") + if not function_evaluated: + return + assert_input(page, "20") + + page.fill("#input1", "30") + function_evaluated = True + try: + page.wait_for_function("document.querySelector('#val1').innerText !== '20'") + function_evaluated = True + except Exception as e: + function_evaluated = False + logging.getLogger().debug(f"Function evaluation timeout.\n{e}") + if not function_evaluated: + return + assert_input(page, "30") + + +def assert_input(page: "Page", val: str): + val1 = page.query_selector("#val1").inner_text() + assert str(val1).startswith(val) + val2 = page.query_selector("#val2").inner_text() + assert str(val2).startswith(f"Val: {val}") + inp1 = page.input_value("input#input1") + assert str(inp1).startswith(val) + inp2 = page.input_value("#input2 input") + assert str(inp2).startswith(val) + + +@pytest.mark.filterwarnings("ignore::Warning") +@pytest.mark.teste2e +def test_slider_input_reload(page: "Page", gui: Gui, helpers): + page_md = """ +#Test Multi Number + +<|{val}|id=val1|> + +<|Val: {val}|id=val2|> + +<|{val}|number|id=input1|> + +<|{val}|slider|id=input2|> +""" + val = 0 + gui._set_frame(inspect.currentframe()) + gui.add_page(name="page1", page=page_md) + helpers.run_e2e_multi_client(gui) + page.goto("/page1") + page.expect_websocket() + page.wait_for_selector("#val1") + edit_and_assert_page(page) + + page.reload() + page.expect_websocket() + page.wait_for_selector("#val1") + assert_input(page, "30") + + page.evaluate("window.localStorage.removeItem('TaipyClientId')") + + page.reload() + page.expect_websocket() + page.wait_for_selector("#val1") + assert_input(page, "0") diff --git a/tests/taipy/gui/helpers.py b/tests/taipy/gui/helpers.py index fcda2a420..e7a6fb8d1 100644 --- a/tests/taipy/gui/helpers.py +++ b/tests/taipy/gui/helpers.py @@ -117,8 +117,23 @@ def run_e2e(gui, **kwargs): kwargs["run_in_thread"] = True kwargs["single_client"] = True kwargs["run_browser"] = False - kwargs["locals_bind"] = t.cast(FrameType, inspect.currentframe().f_back).f_locals with warnings.catch_warnings(record=True): gui.run(**kwargs) while not Helpers.port_check(): time.sleep(0.1) + + @staticmethod + def run_e2e_multi_client(gui: Gui): + with warnings.catch_warnings(record=True): + gui.run(run_server=False, run_browser=False, single_client=False) + gui._server.runWithWS( + host=gui._get_config("host", "127.0.0.1"), + port=gui._get_config("port", 5000), + debug=False, + use_reloader=False, + flask_log=False, + run_in_thread=True, + ssl_context=None, + ) + while not Helpers.port_check(): + time.sleep(0.1) diff --git a/tests/taipy/gui/notebook/simple_gui.ipynb b/tests/taipy/gui/notebook/simple_gui.ipynb index cd7faf5df..369172666 100644 --- a/tests/taipy/gui/notebook/simple_gui.ipynb +++ b/tests/taipy/gui/notebook/simple_gui.ipynb @@ -66,7 +66,7 @@ }, "outputs": [], "source": [ - "gui.run()" + "gui.run(run_browser=False)" ] }, { @@ -94,7 +94,7 @@ }, "outputs": [], "source": [ - "gui.run()" + "gui.run(run_browser=False)" ] }, {