Переглянути джерело

fix page scopes issue importing * (#1689) (#1694)

Dinh Long Nguyen 8 місяців тому
батько
коміт
af60cf75b4

+ 7 - 1
taipy/gui/utils/get_imported_var.py

@@ -14,6 +14,8 @@ import inspect
 import typing as t
 from types import FrameType
 
+from .get_module_name import _get_absolute_module_name_from_ast, _get_module_name_from_frame
+
 
 def _get_imported_var(frame: FrameType) -> t.List[t.Tuple[str, str, str]]:
     st = ast.parse(inspect.getsource(frame))
@@ -22,11 +24,15 @@ def _get_imported_var(frame: FrameType) -> t.List[t.Tuple[str, str, str]]:
         if isinstance(node, ast.ImportFrom):
             # get the imported element as (name, asname, module)
             # ex: from module1 import a as x --> ("a", "x", "module1")
+            frame_module_name = _get_module_name_from_frame(frame)
+            node_module_name = ""
+            if node.module and frame_module_name:
+                node_module_name = _get_absolute_module_name_from_ast(str(frame_module_name), node.module, node.level)
             var_list.extend(
                 (
                     child_node.name,
                     child_node.asname if child_node.asname is not None else child_node.name,
-                    node.module or "",
+                    node_module_name,
                 )
                 for child_node in node.names
             )

+ 16 - 0
taipy/gui/utils/get_module_name.py

@@ -13,6 +13,8 @@ import sys
 import typing as t
 from types import FrameType
 
+from .._warnings import _warn
+
 
 def _get_module_name_from_frame(frame: FrameType):
     return frame.f_globals["__name__"] if "__name__" in frame.f_globals else None
@@ -29,3 +31,17 @@ def _get_module_name_from_imported_var(var_name: str, value: t.Any, sub_module_n
             return m
     # failed fetching any matched module with variable and value
     return sub_module_name
+
+
+def _get_absolute_module_name_from_ast(based_module: str, relative_module: str, level: int) -> str:
+    # Level 0 == absolute module path
+    # Level 1 == relative to the current module
+    if level == 0:
+        return relative_module
+    based_module_name_list = based_module.split(".")
+    if level > len(based_module_name_list):
+        _warn(
+            f"There is an error resolving the absolute module path for {relative_module}. The application might behave unexpectedly."  # noqa: E501
+        )
+        return relative_module
+    return ".".join(based_module_name_list[:-level] + [relative_module])

+ 0 - 0
tests/gui/e2e/page_scopes/assets5_import_all/__init__.py


+ 0 - 0
tests/gui/e2e/page_scopes/assets5_import_all/folder1/__init__.py


+ 4 - 0
tests/gui/e2e/page_scopes/assets5_import_all/folder1/content1.py

@@ -0,0 +1,4 @@
+a = 10
+
+def update_a(state):
+    state.a = 20

+ 4 - 0
tests/gui/e2e/page_scopes/assets5_import_all/folder1/content2.py

@@ -0,0 +1,4 @@
+b = 20
+
+def update_b(state):
+    state.b = 40

+ 14 - 0
tests/gui/e2e/page_scopes/assets5_import_all/page1.py

@@ -0,0 +1,14 @@
+from taipy.gui import Markdown
+
+from .folder1.content1 import a, update_a  # noqa: F401
+from .folder1.content2 import *  # noqa: F403
+
+page = Markdown(
+"""
+<|{a}|id=num_a|>
+<|btna|button|on_action=update_a|id=btn_a|>
+<|{b}|id=num_b|>
+<|btnb|button|on_action=update_b|id=btn_b|>
+"""
+)
+

+ 63 - 0
tests/gui/e2e/page_scopes/test_page_scopes_import_all.py

@@ -0,0 +1,63 @@
+# Copyright 2021-2024 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
+
+from taipy.gui import Gui
+
+if util.find_spec("playwright"):
+    from playwright._impl._page import Page
+
+from .assets5_import_all.page1 import page as page1
+
+
+def helpers_assert_value(page, numa, numb):
+    assert page.query_selector("#num_a").inner_text() == numa
+    assert page.query_selector("#num_b").inner_text() == numb
+
+@pytest.mark.timeout(300)
+@pytest.mark.teste2e
+@pytest.mark.filterwarnings("ignore::Warning")
+def test_page_scopes_import_all(page: "Page", gui: Gui, helpers):
+    gui._set_frame(inspect.currentframe())
+    gui.add_page("page1", page1)
+    helpers.run_e2e(gui)
+
+    page.goto("./page1")
+    page.expect_websocket()
+    page.wait_for_selector("#num_a")
+    helpers_assert_value(page, "10", "20")
+    page.click("#btn_a")
+    function_evaluated = True
+    try:
+        page.wait_for_function("document.querySelector('#num_a').innerText !== '10'")
+        function_evaluated = True
+    except Exception as e:
+        function_evaluated = False
+        logging.getLogger().debug(f"Function evaluation timeout.\n{e}")
+    if not function_evaluated:
+        return
+    helpers_assert_value(page, "20", "20")
+    page.click("#btn_b")
+    function_evaluated = True
+    try:
+        page.wait_for_function("document.querySelector('#num_b').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
+    helpers_assert_value(page, "20", "40")