Browse Source

support glob declaration in resource descriptions (#2192)

* support glob declaration in resource descriptions

* use Path.glob to be 3.9 compatible

---------

Co-authored-by: Fred Lefévère-Laoide <Fred.Lefevere-Laoide@Taipy.io>
Fred Lefévère-Laoide 6 tháng trước cách đây
mục cha
commit
5b484794f6
3 tập tin đã thay đổi với 30 bổ sung19 xóa
  1. 22 6
      taipy/gui/extension/library.py
  2. 5 10
      taipy/gui/gui.py
  3. 3 3
      taipy/gui_core/_GuiCoreLib.py

+ 22 - 6
taipy/gui/extension/library.py

@@ -16,7 +16,7 @@ import xml.etree.ElementTree as etree
 from abc import ABC, abstractmethod
 from inspect import isclass
 from pathlib import Path
-from urllib.parse import urlencode
+from urllib.parse import urlencode, urlparse
 
 from .._renderers.builder import _Builder
 from .._warnings import _warn
@@ -115,7 +115,7 @@ class Element:
             default_property (str): The name of the default property for this element.
             properties (Dict[str, ElementProperty]): The dictionary containing the properties of this element, where the keys are the property names and the values are instances of ElementProperty.
             inner_properties (Optional[List[ElementProperty]]): The optional list of inner properties for this element.<br/>
-                Default values are set/binded automatically.
+                Default values are set/bound automatically.
             react_component (Optional[str]): The name of the component to be created on the front-end.<br/>
                 If not specified, it is set to a camel case version of the element's name
                 ("one_name" is transformed to "OneName").
@@ -324,9 +324,27 @@ class ElementLibrary(ABC):
         """
         return _to_camel_case(self.get_name(), True)
 
+    def __get_class_folder(self):
+        if not hasattr(self, "_class_folder"):
+            module_obj = sys.modules.get(self.__class__.__module__)
+            base = (Path(".") if module_obj is None else Path(module_obj.__file__).parent).resolve()  # type: ignore
+            self._class_folder = base if base.exists() else Path(".").resolve()
+        return self._class_folder
+
+    def _do_get_relative_paths(self, paths: t.List[str]) -> t.List[str]:
+        ret = set()
+        for path in paths or []:
+            if bool(urlparse(path).netloc):
+                ret.add(path)
+            elif file_paths := self.__get_class_folder().glob(path):
+                ret.update([file_path.relative_to(self.__get_class_folder()).as_posix() for file_path in file_paths])
+            elif path:
+                ret.add(path)
+        return list(ret)
+
     def get_scripts(self) -> t.List[str]:
         """
-        Return the list of the mandatory script file pathnames.
+        Return the list of the mandatory script file path names.
 
         If a script file pathname is an absolute URL it will be used as is.<br/>
         If it's not it will be passed to `(ElementLibrary.)get_resource()^` to retrieve a local
@@ -363,9 +381,7 @@ class ElementLibrary(ABC):
         Arguments:
             name (str): The name of the resource for which a local Path should be returned.
         """  # noqa: E501
-        module_obj = sys.modules.get(self.__class__.__module__)
-        base = (Path(".") if module_obj is None else Path(module_obj.__file__).parent).resolve()  # type: ignore
-        base = base if base.exists() else Path(".").resolve()
+        base = self.__get_class_folder()
         file = (base / name).resolve()
         if str(file).startswith(str(base)) and file.exists():
             return file

+ 5 - 10
taipy/gui/gui.py

@@ -1332,12 +1332,8 @@ class Gui:
         )
 
     def __send_ws_alert(
-            self, type: str,
-            message: str,
-            system_notification: bool,
-            duration: int,
-            notification_id: t.Optional[str] = None
-        ) -> None:
+        self, type: str, message: str, system_notification: bool, duration: int, notification_id: t.Optional[str] = None
+    ) -> None:
         payload = {
             "type": _WsType.ALERT.value,
             "atype": type,
@@ -2278,10 +2274,9 @@ class Gui:
                 message="",  # No need for a message when closing
                 system_notification=False,  # System notification not needed for closing
                 duration=0,  # No duration since it's an immediate close
-                notification_id=notification_id
+                notification_id=notification_id,
             )
 
-
     def _hold_actions(
         self,
         callback: t.Optional[t.Union[str, t.Callable]] = None,
@@ -2661,13 +2656,13 @@ class Gui:
             s if bool(urlparse(s).netloc) else f"{Gui._EXTENSION_ROOT}/{name}/{s}{lib.get_query(s)}"
             for name, libs in Gui.__extensions.items()
             for lib in libs
-            for s in (lib.get_scripts() or [])
+            for s in (lib._do_get_relative_paths(lib.get_scripts()))
         ]
         styles = [
             s if bool(urlparse(s).netloc) else f"{Gui._EXTENSION_ROOT}/{name}/{s}{lib.get_query(s)}"
             for name, libs in Gui.__extensions.items()
             for lib in libs
-            for s in (lib.get_styles() or [])
+            for s in (lib._do_get_relative_paths(lib.get_styles()))
         ]
         if self._get_config("stylekit", True):
             styles.append("stylekit/stylekit.css")

+ 3 - 3
taipy/gui_core/_GuiCoreLib.py

@@ -65,7 +65,7 @@ class _GuiCore(ElementLibrary):
     __DATANODE_SELECTOR_SORT_VAR = "__tpgc_dn_sort"
     __DATANODE_SELECTOR_ERROR_VAR = "__tpgc_dn_error"
 
-    __elts = {
+    __elements = {
         "scenario_selector": Element(
             "value",
             {
@@ -314,10 +314,10 @@ class _GuiCore(ElementLibrary):
         return _GuiCore.__LIB_NAME
 
     def get_elements(self) -> t.Dict[str, Element]:
-        return _GuiCore.__elts
+        return _GuiCore.__elements
 
     def get_scripts(self) -> t.List[str]:
-        return ["lib/taipy-gui-core.js"]
+        return ["lib/*.js"]
 
     def on_init(self, gui: Gui) -> t.Optional[t.Tuple[str, t.Any]]:
         self.ctx = _GuiCoreContext(gui)