Explorar el Código

Declare core gui viz elements in tgb if present (#2134)

resolves #1620

Co-authored-by: Fred Lefévère-Laoide <Fred.Lefevere-Laoide@Taipy.io>
Fred Lefévère-Laoide hace 6 meses
padre
commit
f408ab0c76
Se han modificado 2 ficheros con 95 adiciones y 58 borrados
  1. 5 5
      taipy/gui_core/viselements.json
  2. 90 53
      tools/gui/generate_pyi.py

+ 5 - 5
taipy/gui_core/viselements.json

@@ -100,7 +100,7 @@
                     },
                     },
                     {
                     {
                         "name": "filter",
                         "name": "filter",
-                        "type": "bool|str|ScenarioFilter|list[str|ScenarioFilter]",
+                        "type": "bool|str|taipy.gui_core.filters.ScenarioFilter|list[str|taipy.gui_core.filters.ScenarioFilter]",
                         "default_value": "\"*\"",
                         "default_value": "\"*\"",
                         "doc": "TODO: a list of <code>Scenario^</code> attributes to filter on. If False, do not allow filter."
                         "doc": "TODO: a list of <code>Scenario^</code> attributes to filter on. If False, do not allow filter."
                     },
                     },
@@ -112,7 +112,7 @@
                     },
                     },
                     {
                     {
                         "name": "sort",
                         "name": "sort",
-                        "type": "bool|str|ScenarioFilter|list[str|ScenarioFilter]",
+                        "type": "bool|str|taipy.gui_core.filters.ScenarioFilter|list[str|taipy.gui_core.filters.ScenarioFilter]",
                         "default_value": "\"*\"",
                         "default_value": "\"*\"",
                         "doc": "TODO: a list of <code>Scenario^</code> attributes to sort on. If False, do not allow sort."
                         "doc": "TODO: a list of <code>Scenario^</code> attributes to sort on. If False, do not allow sort."
                     }
                     }
@@ -355,7 +355,7 @@
                     },
                     },
                     {
                     {
                         "name": "filter",
                         "name": "filter",
-                        "type": "bool|str|DataNodeFilter|list[str|DataNodeFilter]",
+                        "type": "bool|str|taipy.gui_core.filters.DataNodeFilter|list[str|taipy.gui_core.filters.DataNodeFilter]",
                         "default_value": "\"*\"",
                         "default_value": "\"*\"",
                         "doc": "TODO: a list of <code>DataNode^</code> attributes to filter on. If False, do not allow filter."
                         "doc": "TODO: a list of <code>DataNode^</code> attributes to filter on. If False, do not allow filter."
                     },
                     },
@@ -367,7 +367,7 @@
                     },
                     },
                     {
                     {
                         "name": "sort",
                         "name": "sort",
-                        "type": "bool|str|DataNodeFilter|list[str|DataNodeFilter]",
+                        "type": "bool|str|taipy.gui_core.filters.DataNodeFilter|list[str|taipy.gui_core.filters.DataNodeFilter]",
                         "default_value": "\"*\"",
                         "default_value": "\"*\"",
                         "doc": "TODO: a list of <code>DataNode^</code> attributes to sort on. If False, do not allow sort."
                         "doc": "TODO: a list of <code>DataNode^</code> attributes to sort on. If False, do not allow sort."
                     }
                     }
@@ -548,7 +548,7 @@
                     },
                     },
                     {
                     {
                         "name": "on_details",
                         "name": "on_details",
-                        "type": "Union[str, Callback, bool]",
+                        "type": "Union[str, Callable, bool]",
                         "doc": "The name of a function that is triggered when the details icon is pressed.<br/>The parameters of that function are all optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the id of the control.</li>\n<li>payload (<code>dict</code>): a dictionary that contains the Job Id in the value for key <i>args<i>.</li>\n</ul></br>If False, the icon is not shown.",
                         "doc": "The name of a function that is triggered when the details icon is pressed.<br/>The parameters of that function are all optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the id of the control.</li>\n<li>payload (<code>dict</code>): a dictionary that contains the Job Id in the value for key <i>args<i>.</li>\n</ul></br>If False, the icon is not shown.",
                         "signature": [
                         "signature": [
                             [
                             [

+ 90 - 53
tools/gui/generate_pyi.py

@@ -71,27 +71,44 @@ taipy_doc_url = f"https://docs.taipy.io/en/{current_version}/manuals/userman/gui
 
 
 builder_py_file = "./taipy/gui/builder/__init__.py"
 builder_py_file = "./taipy/gui/builder/__init__.py"
 builder_pyi_file = f"{builder_py_file}i"
 builder_pyi_file = f"{builder_py_file}i"
+controls: Dict[str, List] = {}
+blocks: Dict[str, List] = {}
+undocumented: Dict[str, List] = {}
 with open("./taipy/gui/viselements.json", "r") as file:
 with open("./taipy/gui/viselements.json", "r") as file:
-    viselements = json.load(file)
+    viselements: Dict[str, List] = json.load(file)
+    controls[""] = viselements.get("controls", [])
+    blocks[""] = viselements.get("blocks", [])
+    undocumented[""] = viselements.get("undocumented", [])
+with open("./taipy/gui_core/viselements.json", "r") as file:
+    core_viselements: Dict[str, List] = json.load(file)
+    controls['if find_spec("taipy.core"):'] = core_viselements.get("controls", [])
+    blocks['if find_spec("taipy.core"):'] = core_viselements.get("blocks", [])
+    undocumented['if find_spec("taipy.core"):'] = core_viselements.get("undocumented", [])
+
 os.system(f"pipenv run stubgen {builder_py_file} --no-import --parse-only --export-less -o ./")
 os.system(f"pipenv run stubgen {builder_py_file} --no-import --parse-only --export-less -o ./")
 
 
 with open(builder_pyi_file, "a") as file:
 with open(builder_pyi_file, "a") as file:
     file.write("from datetime import datetime\n")
     file.write("from datetime import datetime\n")
+    file.write("from importlib.util import find_spec\n")
     file.write("from typing import Any, Callable, Optional, Union\n")
     file.write("from typing import Any, Callable, Optional, Union\n")
     file.write("\n")
     file.write("\n")
     file.write("from .. import Icon\n")
     file.write("from .. import Icon\n")
     file.write("from ._element import _Block, _Control\n")
     file.write("from ._element import _Block, _Control\n")
+    file.write('if find_spec("taipy.core"):\n')
+    file.write("\tfrom taipy.core import Cycle, DataNode, Job, Scenario\n")
 
 
 
 
-def resolve_inherit(name: str, properties, inherits, viselements) -> List[Dict[str, Any]]:
+def resolve_inherit(
+    name: str, properties, inherits, blocks: List, controls: List, undocumented: List
+) -> List[Dict[str, Any]]:
     if not inherits:
     if not inherits:
         return properties
         return properties
     for inherit_name in inherits:
     for inherit_name in inherits:
-        inherited_desc = next((e for e in viselements["undocumented"] if e[0] == inherit_name), None)
+        inherited_desc = next((e for e in undocumented if e[0] == inherit_name), None)
         if inherited_desc is None:
         if inherited_desc is None:
-            inherited_desc = next((e for e in viselements["blocks"] if e[0] == inherit_name), None)
+            inherited_desc = next((e for e in blocks if e[0] == inherit_name), None)
         if inherited_desc is None:
         if inherited_desc is None:
-            inherited_desc = next((e for e in viselements["controls"] if e[0] == inherit_name), None)
+            inherited_desc = next((e for e in controls if e[0] == inherit_name), None)
         if inherited_desc is None:
         if inherited_desc is None:
             raise RuntimeError(f"Element type '{name}' inherits from unknown element type '{inherit_name}'")
             raise RuntimeError(f"Element type '{name}' inherits from unknown element type '{inherit_name}'")
         inherited_desc = inherited_desc[1]
         inherited_desc = inherited_desc[1]
@@ -109,11 +126,13 @@ def resolve_inherit(name: str, properties, inherits, viselements) -> List[Dict[s
                 override(prop_desc, inherit_prop, "signature")
                 override(prop_desc, inherit_prop, "signature")
             else:
             else:
                 properties.append(inherit_prop)
                 properties.append(inherit_prop)
-            properties = resolve_inherit(inherit_name, properties, inherited_desc.get("inherits", None), viselements)
+            properties = resolve_inherit(
+                inherit_name, properties, inherited_desc.get("inherits", None), blocks, controls, undocumented
+            )
     return properties
     return properties
 
 
 
 
-def format_as_parameter(property):
+def format_as_parameter(property: Dict[str, str]):
     name = property["name"]
     name = property["name"]
     if match := __RE_INDEXED_PROPERTY.match(name):
     if match := __RE_INDEXED_PROPERTY.match(name):
         name = f"{match.group(1)}__{match.group(3)}"
         name = f"{match.group(1)}__{match.group(3)}"
@@ -130,8 +149,8 @@ def format_as_parameter(property):
         property["dynamic"] = ""
         property["dynamic"] = ""
     if type == "Callback" or type == "Function":
     if type == "Callback" or type == "Function":
         type = "Callable"
         type = "Callable"
-    elif re.match(r"plotly\.", type) or re.match(r"taipy\.", type):
-        type = f"\"{type}\""
+    else:
+        type = re.sub(r"((plotly|taipy)\.[\w\.]*)", r'"\1"', type)
     default_value = property.get("default_value", None)
     default_value = property.get("default_value", None)
     if default_value is None or default_value == "None":
     if default_value is None or default_value == "None":
         default_value = " = None"
         default_value = " = None"
@@ -159,7 +178,7 @@ def build_doc(name: str, desc: Dict[str, Any]):
         doc = doc.replace("[element_type]", name)
         doc = doc.replace("[element_type]", name)
     # This won't work for Scenario Management and Block elements
     # This won't work for Scenario Management and Block elements
     doc = re.sub(r"(href=\")\.\.((?:.*?)\")", r"\1" + taipy_doc_url + name + r"/../..\2", doc)
     doc = re.sub(r"(href=\")\.\.((?:.*?)\")", r"\1" + taipy_doc_url + name + r"/../..\2", doc)
-    doc = re.sub(r"<tt>([\w_]+)</tt>", r"`\1`", doc) # <tt> not processed properly by markdownify()
+    doc = re.sub(r"<tt>([\w_]+)</tt>", r"`\1`", doc)  # <tt> not processed properly by markdownify()
     doc = "\n  ".join(markdownify(doc).split("\n"))
     doc = "\n  ".join(markdownify(doc).split("\n"))
     # <, >, `, [, -, _ and * prefixed with a \
     # <, >, `, [, -, _ and * prefixed with a \
     doc = doc.replace("  \n", "  \\n").replace("\\<", "<").replace("\\>", ">").replace("\\`", "`")
     doc = doc.replace("  \n", "  \\n").replace("\\<", "<").replace("\\>", ">").replace("\\`", "`")
@@ -172,56 +191,74 @@ def build_doc(name: str, desc: Dict[str, Any]):
     return f"{desc['name']}{desc['dynamic']}{desc['indexed']}\\n  {doc}\\n\\n"
     return f"{desc['name']}{desc['dynamic']}{desc['indexed']}\\n  {doc}\\n\\n"
 
 
 
 
-element_template = """
+def element_template(name: str, base_class: str, n: str, properties_decl: str, properties_doc: str, ind: str):
+    return f"""
 
 
-class {{name}}(_{{base_class}}):
-    _ELEMENT_NAME: str
-    def __init__(self, {{properties_decl}}) -> None:
-        \"\"\"Creates a{{n}} {{name}} element.\\n\\nParameters\\n----------\\n\\n{{properties_doc}}\"\"\"  # noqa: E501
-        ...
+{ind}class {name}(_{base_class}):
+{ind}    _ELEMENT_NAME: str
+{ind}    def __init__(self, {properties_decl}) -> None:
+{ind}        \"\"\"Creates a{n} {name} element.\\n\\nParameters\\n----------\\n\\n{properties_doc}\"\"\"  # noqa: E501
+{ind}        ...
 """
 """
 
 
 
 
-def generate_elements(category: str, base_class: str):
-    for element in viselements[category]:
-        name = element[0]
-        desc = element[1]
-        properties_doc = ""
-        property_list: List[Dict[str, Any]] = []
-        property_names: List[str] = []
-        properties = resolve_inherit(name, desc["properties"], desc.get("inherits", None), viselements)
-        # Remove hidden properties
-        properties = [p for p in properties if not p.get("hide", False)]
-        # Generate function parameters
-        properties_decl = [format_as_parameter(p) for p in properties]
-        # Generate properties doc
-        for property in properties:
-            if "default_property" in property and property["default_property"] is True:
-                property_list.insert(0, property)
-                property_names.insert(0, property["name"])
-                continue
-            property_list.append(property)
-            property_names.append(property["name"])
-        # Append properties doc to element doc (once ordered)
-        for property in property_list:
-            property_doc = build_doc(name, property)
-            properties_doc += property_doc
-        if len(properties_decl) > 1:
-            properties_decl.insert(1, "*")
-        # Append element to __init__.pyi
-        with open(builder_pyi_file, "a") as file:
-            n = "n" if name[0] in ["a", "e", "i", "o"] else ""
-            file.write(
-                element_template.replace("{{name}}", name)
-                .replace("{{n}}", n)
-                .replace("{{base_class}}", base_class)
-                .replace("{{properties_decl}}", ", ".join(properties_decl))
-                .replace("{{properties_doc}}", properties_doc)
+def generate_elements(elements_by_prefix: Dict[str, List], base_class: str):
+    for prefix, elements in elements_by_prefix.items():
+        if not elements:
+            continue
+        indent = ""
+        if prefix:
+            indent = "    "
+            with open(builder_pyi_file, "a") as file:
+                file.write(prefix + "\n")
+        for element in elements:
+            name = element[0]
+            desc = element[1]
+            properties_doc = ""
+            property_list: List[Dict[str, Any]] = []
+            property_names: List[str] = []
+            properties = resolve_inherit(
+                name,
+                desc["properties"],
+                desc.get("inherits", None),
+                blocks.get(prefix, []),
+                controls.get(prefix, []),
+                undocumented.get(prefix, []),
             )
             )
+            # Remove hidden properties
+            properties = [p for p in properties if not p.get("hide", False)]
+            # Generate function parameters
+            properties_decl = [format_as_parameter(p) for p in properties]
+            # Generate properties doc
+            for property in properties:
+                if "default_property" in property and property["default_property"] is True:
+                    property_list.insert(0, property)
+                    property_names.insert(0, property["name"])
+                    continue
+                property_list.append(property)
+                property_names.append(property["name"])
+            # Append properties doc to element doc (once ordered)
+            for property in property_list:
+                property_doc = build_doc(name, property)
+                properties_doc += property_doc
+            if len(properties_decl) > 1:
+                properties_decl.insert(1, "*")
+            # Append element to __init__.pyi
+            with open(builder_pyi_file, "a") as file:
+                file.write(
+                    element_template(
+                        name,
+                        base_class,
+                        "n" if name[0] in ["a", "e", "i", "o"] else "",
+                        ", ".join(properties_decl),
+                        properties_doc,
+                        indent,
+                    )
+                )
 
 
 
 
-generate_elements("controls", "Control")
-generate_elements("blocks", "Block")
+generate_elements(controls, "Control")
+generate_elements(blocks, "Block")
 
 
 os.system(f"pipenv run isort {gui_pyi_file}")
 os.system(f"pipenv run isort {gui_pyi_file}")
 os.system(f"pipenv run black {gui_pyi_file}")
 os.system(f"pipenv run black {gui_pyi_file}")