1
0
Эх сурвалжийг харах

Improve content of generated pyi for the Page Builder API (#1653)

- Change Page Builder API pyi generation script
- Updated actions
- Details in element examples
Fabien Lelaquais 9 сар өмнө
parent
commit
39f5a454c8

+ 1 - 1
.github/actions/gui-test/pyi/action.yml

@@ -8,7 +8,7 @@ runs:
       run: pipenv run pip install mypy black isort
       run: pipenv run pip install mypy black isort
     - name: Generate pyi
     - name: Generate pyi
       shell: bash
       shell: bash
-      run: cp tools/gui/generate_pyi.py pyi_temp.py && pipenv run python pyi_temp.py && rm pyi_temp.py
+      run: pipenv run python tools/gui/generate_pyi.py
     - name: Cleanup any untracked files
     - name: Cleanup any untracked files
       shell: bash
       shell: bash
       run: git clean -f
       run: git clean -f

+ 1 - 1
.github/workflows/build-and-release-single-package.yml

@@ -128,7 +128,7 @@ jobs:
       - name: Generate GUI pyi file
       - name: Generate GUI pyi file
         if: github.event.inputs.target_package == 'gui'
         if: github.event.inputs.target_package == 'gui'
         run: |
         run: |
-          cp tools/gui/generate_pyi.py pyi_temp.py && pipenv run python pyi_temp.py && rm pyi_temp.py
+          pipenv run python tools/gui/generate_pyi.py
 
 
       - name: Build frontends
       - name: Build frontends
         if: github.event.inputs.target_package == 'gui'
         if: github.event.inputs.target_package == 'gui'

+ 1 - 1
.github/workflows/build-and-release.yml

@@ -126,7 +126,7 @@ jobs:
       - name: Generate GUI pyi file
       - name: Generate GUI pyi file
         if: matrix.package == 'gui'
         if: matrix.package == 'gui'
         run: |
         run: |
-          cp tools/gui/generate_pyi.py pyi_temp.py && pipenv run python pyi_temp.py && rm pyi_temp.py
+          pipenv run python tools/gui/generate_pyi.py
 
 
       - name: Build frontends
       - name: Build frontends
         if: matrix.package == 'gui'
         if: matrix.package == 'gui'

+ 2 - 1
doc/gui/examples/controls/chat-discuss.py

@@ -19,12 +19,13 @@
 # incognito windows so a given user's context is not reused.
 # incognito windows so a given user's context is not reused.
 # -----------------------------------------------------------------------------------------
 # -----------------------------------------------------------------------------------------
 from os import path
 from os import path
+from typing import Union
 
 
 from taipy.gui import Gui, Icon
 from taipy.gui import Gui, Icon
 from taipy.gui.gui_actions import navigate, notify
 from taipy.gui.gui_actions import navigate, notify
 
 
 username = ""
 username = ""
-users: list[str | Icon] = []
+users: list[Union[str, Icon]] = []
 messages: list[tuple[str, str, str]] = []
 messages: list[tuple[str, str, str]] = []
 
 
 Gui.add_shared_variables("messages", "users")
 Gui.add_shared_variables("messages", "users")

+ 15 - 15
doc/gui/examples/controls/metric-color-map.py

@@ -15,23 +15,23 @@
 # -----------------------------------------------------------------------------------------
 # -----------------------------------------------------------------------------------------
 from taipy.gui import Gui
 from taipy.gui import Gui
 
 
-# color_map = {
-#     # 0-20 - Let Taipy decide
-#     # 20-40 - red
-#     20: "red",
-#     # 40-60 - Let Taipy decide
-#     40: None,
-#     # 60-80 - blue
-#     60: "blue",
-#     # 80-100 - Let Taipy decide
-#     80: None
-# }
-
-value = 50
-color_map = {20: "red", 40: None, 60: "blue", 80: None}
+# Color wavelength
+color_wl = 530
+# Color ranges by wavelength
+color_map = {
+    200: None,
+    380: "violet",
+    435: "blue",
+    500: "cyan",
+    520: "green",
+    565: "yellow",
+    590: "orange",
+    625: "red",
+    740: None,
+}
 
 
 page = """
 page = """
-<|{value}|metric|color_map={color_map}|>
+<|{color_wl}|metric|color_map={color_map}|format=%d nm|min=200|max=800|bar_color=gray|>
 """
 """
 
 
 Gui(page).run()
 Gui(page).run()

+ 1 - 1
doc/gui/examples/controls/metric-layout.py

@@ -15,7 +15,7 @@
 # -----------------------------------------------------------------------------------------
 # -----------------------------------------------------------------------------------------
 from taipy.gui import Gui
 from taipy.gui import Gui
 
 
-value = 50
+value = 45
 # The layout object reference can be found in Plotly's documentation:
 # The layout object reference can be found in Plotly's documentation:
 #         https://plotly.com/python/reference/layout/
 #         https://plotly.com/python/reference/layout/
 layout = {
 layout = {

+ 4 - 5
doc/gui/examples/controls/metric-simple.py

@@ -15,13 +15,12 @@
 # -----------------------------------------------------------------------------------------
 # -----------------------------------------------------------------------------------------
 from taipy.gui import Gui
 from taipy.gui import Gui
 
 
-value = 50
-max_value = 150
-delta_value = 20
-threshold = 100
+value = 72
+delta = 15
+threshold = 60
 
 
 page = """
 page = """
-<|{value}|metric|max={max_value}|delta={delta_value}|threshold={threshold}|>
+<|{value}|metric|delta={delta}|threshold={threshold}|>
 """
 """
 
 
 Gui(page).run()
 Gui(page).run()

+ 59 - 63
taipy/gui/viselements.json

@@ -44,14 +44,14 @@
                     {
                     {
                         "name": "label",
                         "name": "label",
                         "default_property": true,
                         "default_property": true,
-                        "type": "dynamic(str|Icon)",
+                        "type": "dynamic(Union[str,Icon])",
                         "default_value": "\"\"",
                         "default_value": "\"\"",
                         "doc": "The label displayed in the button."
                         "doc": "The label displayed in the button."
                     },
                     },
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of a function that is triggered when the button 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|None): the identifier of the button.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
+                        "doc": "The name of a function that is triggered when the button 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 identifier of the button it it has one.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -142,24 +142,24 @@
                     },
                     },
                     {
                     {
                         "name": "step",
                         "name": "step",
-                        "type": "dynamic(int|float)",
+                        "type": "dynamic(Union[int,float])",
                         "default_value": "1",
                         "default_value": "1",
                         "doc": "The amount by which the value is incremented or decremented when the user clicks one of the arrow buttons."
                         "doc": "The amount by which the value is incremented or decremented when the user clicks one of the arrow buttons."
                     },
                     },
                     {
                     {
                         "name": "step_multiplier",
                         "name": "step_multiplier",
-                        "type": "dynamic(int|float)",
+                        "type": "dynamic(Union[int,float])",
                         "default_value": "10",
                         "default_value": "10",
                         "doc": "A factor that multiplies <i>step</i> when the user presses the Shift key while clicking one of the arrow buttons."
                         "doc": "A factor that multiplies <i>step</i> when the user presses the Shift key while clicking one of the arrow buttons."
                     },
                     },
                     {
                     {
                         "name": "min",
                         "name": "min",
-                        "type": "dynamic(int|float)",
+                        "type": "dynamic(Union[int,float])",
                         "doc": "The minimum value to accept for this input."
                         "doc": "The minimum value to accept for this input."
                     },
                     },
                     {
                     {
                         "name": "max",
                         "name": "max",
-                        "type": "dynamic(int|float)",
+                        "type": "dynamic(Union[int,float])",
                         "doc": "The maximum value to accept for this input."
                         "doc": "The maximum value to accept for this input."
                     }
                     }
                 ]
                 ]
@@ -176,26 +176,26 @@
                     {
                     {
                         "name": "value",
                         "name": "value",
                         "default_property": true,
                         "default_property": true,
-                        "type": "dynamic(int|float|int[]|float[]|str|str[])",
+                        "type": "dynamic(Union[int,float,str,list[int],list[float],list[str]])",
                         "doc": "The value that is set for this slider.<br/>If this slider is based on a <i>lov</i> then this property can be set to the lov element.<br/>This value can also hold an array of numbers to indicate that the slider reflects a range (within the [<i>min</i>,<i>max</i>] domain) defined by several knobs that the user can set independently.<br/>If this slider is based on a <i>lov</i> then this property can be set to an array of lov elements. The slider is then represented with several knobs, one for each lov value."
                         "doc": "The value that is set for this slider.<br/>If this slider is based on a <i>lov</i> then this property can be set to the lov element.<br/>This value can also hold an array of numbers to indicate that the slider reflects a range (within the [<i>min</i>,<i>max</i>] domain) defined by several knobs that the user can set independently.<br/>If this slider is based on a <i>lov</i> then this property can be set to an array of lov elements. The slider is then represented with several knobs, one for each lov value."
                     },
                     },
                     {
                     {
                         "name": "min",
                         "name": "min",
-                        "type": "int|float",
+                        "type": "Union[int,float]",
                         "default_value": "0",
                         "default_value": "0",
                         "doc": "The minimum value.<br/>This is ignored when <i>lov</i> is defined."
                         "doc": "The minimum value.<br/>This is ignored when <i>lov</i> is defined."
                     },
                     },
                     {
                     {
                         "name": "max",
                         "name": "max",
-                        "type": "int|float",
+                        "type": "Union[int,float]",
                         "default_value": "100",
                         "default_value": "100",
                         "doc": "The maximum value.<br/>This is ignored when <i>lov</i> is defined."
                         "doc": "The maximum value.<br/>This is ignored when <i>lov</i> is defined."
                     },
                     },
                     {
                     {
                         "name": "step",
                         "name": "step",
-                        "type": "int|float",
+                        "type": "Union[int,float]",
                         "default_value": "1",
                         "default_value": "1",
-                        "doc": "The step value: the gap between two consecutive values the slider set. It is a good practice to have (<i>max</i>-<i>min</i>) being divisible by <i>step</i>.<br/>This property is ignored when <i>lov</i> is defined."
+                        "doc": "The step value, which is the gap between two consecutive values the slider set. It is a good practice to have (<i>max</i>-<i>min</i>) being divisible by <i>step</i>.<br/>This property is ignored when <i>lov</i> is defined."
                     },
                     },
                     {
                     {
                         "name": "text_anchor",
                         "name": "text_anchor",
@@ -205,7 +205,7 @@
                     },
                     },
                     {
                     {
                         "name": "labels",
                         "name": "labels",
-                        "type": "bool|dict",
+                        "type": "Union[bool,dict[str,str]]",
                         "doc": "The labels for specific points of the slider.<br/>If set to True, this slider uses the labels of the <i>lov</i> if there are any.<br/>If set to a dictionary, the slider uses the dictionary keys as a <i>lov</i> key or index, and the associated value as the label."
                         "doc": "The labels for specific points of the slider.<br/>If set to True, this slider uses the labels of the <i>lov</i> if there are any.<br/>If set to a dictionary, the slider uses the dictionary keys as a <i>lov</i> key or index, and the associated value as the label."
                     },
                     },
                     {
                     {
@@ -501,7 +501,7 @@
                     {
                     {
                         "name": "on_range_change",
                         "name": "on_range_change",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The callback function that is invoked when the visible part of the x axis changes.<br/>The function receives three parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the chart control.</li>\n<li>payload (dict[str, any]): the full details on this callback's invocation, as emitted by <a href=\"https://plotly.com/javascript/plotlyjs-events/#update-data\">Plotly</a>.</li>\n</ul>",
+                        "doc": "The callback function that is invoked when the visible part of the x axis changes.<br/>The function receives three parameters:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the chart control if it has one.</li>\n<li>payload (dict[str, any]): the full details on this callback's invocation, as emitted by <a href=\"https://plotly.com/javascript/plotlyjs-events/#update-data\">Plotly</a>.</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -519,7 +519,7 @@
                     },
                     },
                     {
                     {
                         "name": "columns",
                         "name": "columns",
-                        "type": "str|list[str]|dict[str, dict[str, str]]",
+                        "type": "Union[str,list[str],dict[str,dict[str,str]]]",
                         "default_value": "<i>All columns</i>",
                         "default_value": "<i>All columns</i>",
                         "doc": "The list of column names\n<ul>\n<li>str: ;-separated list of column names</li>\n<li>list[str]: list of names</li>\n<li>dict: {\"column_name\": {format: \"format\", index: 1}} if index is specified, it represents the display order of the columns.\nIf not, the list order defines the index</li>\n</ul>"
                         "doc": "The list of column names\n<ul>\n<li>str: ;-separated list of column names</li>\n<li>list[str]: list of names</li>\n<li>dict: {\"column_name\": {format: \"format\", index: 1}} if index is specified, it represents the display order of the columns.\nIf not, the list order defines the index</li>\n</ul>"
                     },
                     },
@@ -535,7 +535,7 @@
                     },
                     },
                     {
                     {
                         "name": "selected",
                         "name": "selected",
-                        "type": "indexed(dynamic(list[int]|str))",
+                        "type": "indexed(dynamic(Union[list[int],str]))",
                         "doc": "The list of the selected point indices  ."
                         "doc": "The list of the selected point indices  ."
                     },
                     },
                     {
                     {
@@ -555,7 +555,7 @@
                     },
                     },
                     {
                     {
                         "name": "line",
                         "name": "line",
-                        "type": "indexed(str|dict[str, any])",
+                        "type": "indexed(Union[str,dict[str,any]])",
                         "doc": "The configuration of the line used for the indicated trace.<br/>See <a href=\"https://plotly.com/javascript/reference/scatter/#scatter-line\">line</a> for details.<br/>If the value is a string, it must be a dash type or pattern (see <a href=\"https://plotly.com/python/reference/scatter/#scatter-line-dash\">dash style of lines</a> for details)."
                         "doc": "The configuration of the line used for the indicated trace.<br/>See <a href=\"https://plotly.com/javascript/reference/scatter/#scatter-line\">line</a> for details.<br/>If the value is a string, it must be a dash type or pattern (see <a href=\"https://plotly.com/python/reference/scatter/#scatter-line-dash\">dash style of lines</a> for details)."
                     },
                     },
                     {
                     {
@@ -600,13 +600,13 @@
                     },
                     },
                     {
                     {
                         "name": "width",
                         "name": "width",
-                        "type": "str|int|float",
+                        "type": "Union[str,int,float]",
                         "default_value": "\"100%\"",
                         "default_value": "\"100%\"",
                         "doc": "The width of this chart, in CSS units."
                         "doc": "The width of this chart, in CSS units."
                     },
                     },
                     {
                     {
                         "name": "height",
                         "name": "height",
-                        "type": "str|int|float",
+                        "type": "Union[str,int,float]",
                         "doc": "The height of this chart, in CSS units."
                         "doc": "The height of this chart, in CSS units."
                     },
                     },
                     {
                     {
@@ -689,18 +689,18 @@
                     },
                     },
                     {
                     {
                         "name": "selected",
                         "name": "selected",
-                        "type": "dynamic(list[int]|str)",
+                        "type": "dynamic(Union[list[int],str])",
                         "doc": "The list of the indices of the rows to be displayed as selected."
                         "doc": "The list of the indices of the rows to be displayed as selected."
                     },
                     },
                     {
                     {
                         "name": "page_size_options",
                         "name": "page_size_options",
-                        "type": "list[int]|str",
-                        "default_value": "[50, 100, 500]",
+                        "type": "Union[list[int],str]",
+                        "default_value": "(50, 100, 500)",
                         "doc": "The list of available page sizes that users can choose from."
                         "doc": "The list of available page sizes that users can choose from."
                     },
                     },
                     {
                     {
                         "name": "columns",
                         "name": "columns",
-                        "type": "str|list[str]|dict[str, dict[str, str|int]]",
+                        "type": "Union[str,list[str],dict[str,dict[str,Union[str,int]]]]",
                         "default_value": "<i>shows all columns when empty</i>",
                         "default_value": "<i>shows all columns when empty</i>",
                         "doc": "The list of the column names to display.\n<ul>\n<li>str: Semicolon (';')-separated list of column names.</li>\n<li>list[str]: The list of column names.</li>\n<li>dict: A dictionary with entries matching: {\"col name\": {format: \"format\", index: 1}}.<br/>\nif <i>index</i> is specified, it represents the display order of the columns.\nIf <i>index</i> is not specified, the list order defines the index.<br/>\nIf <i>format</i> is specified, it is used for numbers or dates.</li>\n</ul>"
                         "doc": "The list of the column names to display.\n<ul>\n<li>str: Semicolon (';')-separated list of column names.</li>\n<li>list[str]: The list of column names.</li>\n<li>dict: A dictionary with entries matching: {\"col name\": {format: \"format\", index: 1}}.<br/>\nif <i>index</i> is specified, it represents the display order of the columns.\nIf <i>index</i> is not specified, the list order defines the index.<br/>\nIf <i>format</i> is specified, it is used for numbers or dates.</li>\n</ul>"
                     },
                     },
@@ -885,12 +885,12 @@
                     },
                     },
                     {
                     {
                         "name": "lov[<i>column_name</i>]",
                         "name": "lov[<i>column_name</i>]",
-                        "type": "list[str]|str",
+                        "type": "Union[list[str],str]",
                         "doc": "The list of values of the indicated column."
                         "doc": "The list of values of the indicated column."
                     },
                     },
                     {
                     {
                         "name": "downloadable",
                         "name": "downloadable",
-                        "type": "boolean",
+                        "type": "bool",
                         "doc": "If True, a clickable icon is shown so the user can download the data as CSV."
                         "doc": "If True, a clickable icon is shown so the user can download the data as CSV."
                     },
                     },
                     {
                     {
@@ -954,13 +954,13 @@
                     },
                     },
                     {
                     {
                         "name": "width",
                         "name": "width",
-                        "type": "str|int",
+                        "type": "Union[str,int]",
                         "default_value": "\"360px\"",
                         "default_value": "\"360px\"",
                         "doc": "The width of this selector, in CSS units."
                         "doc": "The width of this selector, in CSS units."
                     },
                     },
                     {
                     {
                         "name": "height",
                         "name": "height",
-                        "type": "str|int",
+                        "type": "Union[str,int]",
                         "doc": "The height of this selector, in CSS units."
                         "doc": "The height of this selector, in CSS units."
                     }
                     }
                 ]
                 ]
@@ -977,7 +977,7 @@
                     {
                     {
                         "name": "content",
                         "name": "content",
                         "default_property": true,
                         "default_property": true,
-                        "type": "dynamic(path|file|URL|ReadableBuffer|None)",
+                        "type": "dynamic(Union[path,file,URL,ReadableBuffer,None])",
                         "doc": "The content to transfer.<br/>If this is a string, a URL, or a file, then the content is read from this source.<br/>If a readable buffer is provided (such as an array of bytes...), and to prevent the bandwidth from being consumed too much, the way the data is transferred depends on the <i>data_url_max_size</i> parameter of the application configuration (which is set to 50kB by default):\n<ul>\n<li>If the buffer size is smaller than this setting, then the raw content is generated as a data URL, encoded using base64 (i.e. <code>\"data:&lt;mimetype&gt;;base64,&lt;data&gt;\"</code>).</li>\n<li>If the buffer size exceeds this setting, then it is transferred through a temporary file.</li>\n</ul>If this property is set to None, that indicates that dynamic content is generated. Please take a look at the examples below for details on dynamic generation."
                         "doc": "The content to transfer.<br/>If this is a string, a URL, or a file, then the content is read from this source.<br/>If a readable buffer is provided (such as an array of bytes...), and to prevent the bandwidth from being consumed too much, the way the data is transferred depends on the <i>data_url_max_size</i> parameter of the application configuration (which is set to 50kB by default):\n<ul>\n<li>If the buffer size is smaller than this setting, then the raw content is generated as a data URL, encoded using base64 (i.e. <code>\"data:&lt;mimetype&gt;;base64,&lt;data&gt;\"</code>).</li>\n<li>If the buffer size exceeds this setting, then it is transferred through a temporary file.</li>\n</ul>If this property is set to None, that indicates that dynamic content is generated. Please take a look at the examples below for details on dynamic generation."
                     },
                     },
                     {
                     {
@@ -988,7 +988,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of a function that is triggered when the download is terminated (or on user action if <i>content</i> is None).<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the button.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has two keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: A list of two elements: <i>args[0]</i> reflects the <i>name</i> property and <i>args[1]</i> holds the file URL.</li>\n</ul>\n</li>\n</ul>",
+                        "doc": "The name of a function that is triggered when the download is terminated (or on user action if <i>content</i> is None).<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button if it has one.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has two keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: A list of two elements: <i>args[0]</i> reflects the <i>name</i> property and <i>args[1]</i> holds the file URL.</li>\n</ul>\n</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1052,7 +1052,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of the function that will be triggered.<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the button.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
+                        "doc": "The name of the function that will be triggered.<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button if it has one.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1106,7 +1106,7 @@
                     {
                     {
                         "name": "content",
                         "name": "content",
                         "default_property": true,
                         "default_property": true,
-                        "type": "dynamic(path|URL|file|ReadableBuffer)",
+                        "type": "dynamic(Union[path,URL,file,ReadableBuffer])",
                         "doc": "The image source.<br/>If a buffer is provided (string, array of bytes...), and in order to prevent the bandwidth to be consumed too much, the way the image data is transferred depends on the <i>data_url_max_size</i> parameter of the application configuration (which is set to 50kB by default):\n<ul>\n<li>If the size of the buffer is smaller than this setting, then the raw content is generated as a\n  data URL, encoded using base64 (i.e. <code>\"data:&lt;mimetype&gt;;base64,&lt;data&gt;\"</code>).</li>\n<li>If the size of the buffer is greater than this setting, then it is transferred through a temporary\n  file.</li>\n</ul>"
                         "doc": "The image source.<br/>If a buffer is provided (string, array of bytes...), and in order to prevent the bandwidth to be consumed too much, the way the image data is transferred depends on the <i>data_url_max_size</i> parameter of the application configuration (which is set to 50kB by default):\n<ul>\n<li>If the size of the buffer is smaller than this setting, then the raw content is generated as a\n  data URL, encoded using base64 (i.e. <code>\"data:&lt;mimetype&gt;;base64,&lt;data&gt;\"</code>).</li>\n<li>If the size of the buffer is greater than this setting, then it is transferred through a temporary\n  file.</li>\n</ul>"
                     },
                     },
                     {
                     {
@@ -1117,7 +1117,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of a function that is triggered when the user clicks on the image.<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the button.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
+                        "doc": "The name of a function that is triggered when the user clicks on the image.<br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button if it has one.</li>\n<li>payload (dict): a dictionary that contains the key \"action\" set to the name of the action that triggered this callback.</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1135,13 +1135,13 @@
                     },
                     },
                     {
                     {
                         "name": "width",
                         "name": "width",
-                        "type": "str|int|float",
+                        "type": "Union[str,int,float]",
                         "default_value": "\"300px\"",
                         "default_value": "\"300px\"",
                         "doc": "The width of this image control, in CSS units."
                         "doc": "The width of this image control, in CSS units."
                     },
                     },
                     {
                     {
                         "name": "height",
                         "name": "height",
-                        "type": "str|int|float",
+                        "type": "Union[str,int,float]",
                         "doc": "The height of this image control, in CSS units."
                         "doc": "The height of this image control, in CSS units."
                     }
                     }
                 ]
                 ]
@@ -1157,7 +1157,7 @@
                     {
                     {
                         "name": "value",
                         "name": "value",
                         "default_property": true,
                         "default_property": true,
-                        "type": "dynamic(int|float)",
+                        "type": "dynamic(Union[int,float])",
                         "doc": "The value to represent."
                         "doc": "The value to represent."
                     },
                     },
                     {
                     {
@@ -1168,19 +1168,19 @@
                     },
                     },
                     {
                     {
                         "name": "min",
                         "name": "min",
-                        "type": "int|float",
+                        "type": "Union[int,float]",
                         "default_value": "0",
                         "default_value": "0",
                         "doc": "The minimum value of this metric control's gauge."
                         "doc": "The minimum value of this metric control's gauge."
                     },
                     },
                     {
                     {
                         "name": "max",
                         "name": "max",
-                        "type": "int|float",
+                        "type": "Union[int,float]",
                         "default_value": "100",
                         "default_value": "100",
                         "doc": "The maximum value of this metric control's gauge."
                         "doc": "The maximum value of this metric control's gauge."
                     },
                     },
                     {
                     {
                         "name": "delta",
                         "name": "delta",
-                        "type": "dynamic(int|float)",
+                        "type": "dynamic(Union[int,float])",
                         "doc": "The delta value to display."
                         "doc": "The delta value to display."
                     },
                     },
                     {
                     {
@@ -1201,7 +1201,7 @@
                     },
                     },
                     {
                     {
                         "name": "threshold",
                         "name": "threshold",
-                        "type": "dynamic(int|float)",
+                        "type": "dynamic(Union[int,float])",
                         "doc": "The threshold value to display."
                         "doc": "The threshold value to display."
                     },
                     },
                     {
                     {
@@ -1232,13 +1232,13 @@
                     },
                     },
                     {
                     {
                         "name": "width",
                         "name": "width",
-                        "type": "str|number",
+                        "type": "Union[str,number]",
                         "default_value": "None",
                         "default_value": "None",
                         "doc": "The width of the metric control, in CSS units."
                         "doc": "The width of the metric control, in CSS units."
                     },
                     },
                     {
                     {
                         "name": "height",
                         "name": "height",
-                        "type": "str|number",
+                        "type": "Union[str,number]",
                         "default_value": "None",
                         "default_value": "None",
                         "doc": "The height of the metric control, in CSS units."
                         "doc": "The height of the metric control, in CSS units."
                     },
                     },
@@ -1317,13 +1317,13 @@
                     },
                     },
                     {
                     {
                         "name": "min",
                         "name": "min",
-                        "type": "int|float",
+                        "type": "Union[int,float]",
                         "default_value": "0",
                         "default_value": "0",
                         "doc": "The minimum value of the range."
                         "doc": "The minimum value of the range."
                     },
                     },
                     {
                     {
                         "name": "max",
                         "name": "max",
-                        "type": "int|float",
+                        "type": "Union[int,float]",
                         "default_value": "100",
                         "default_value": "100",
                         "doc": "The maximum value of the range."
                         "doc": "The maximum value of the range."
                     },
                     },
@@ -1367,14 +1367,14 @@
                     {
                     {
                         "name": "lov",
                         "name": "lov",
                         "default_property": true,
                         "default_property": true,
-                        "type": "dynamic(str|list[str|Icon|any])",
+                        "type": "dynamic(Union[str,list[Union[str,Icon,any]]])",
                         "doc": "The list of menu option values."
                         "doc": "The list of menu option values."
                     },
                     },
                     {
                     {
                         "name": "adapter",
                         "name": "adapter",
                         "type": "Function",
                         "type": "Function",
                         "default_value": "`\"lambda x: str(x)\"`",
                         "default_value": "`\"lambda x: str(x)\"`",
-                        "doc": "The function that transforms an element of <i>lov</i> into a <i>tuple(id:str, label:str|Icon)</i>."
+                        "doc": "The function that transforms an element of <i>lov</i> into a <i>tuple(id:str, label:Union[str,Icon])</i>."
                     },
                     },
                     {
                     {
                         "name": "type",
                         "name": "type",
@@ -1389,7 +1389,7 @@
                     },
                     },
                     {
                     {
                         "name": "inactive_ids",
                         "name": "inactive_ids",
-                        "type": "dynamic(str|list[str])",
+                        "type": "dynamic(Union[str,list[str]])",
                         "doc": "Semicolon (';')-separated list or a list of menu items identifiers that are disabled."
                         "doc": "Semicolon (';')-separated list or a list of menu items identifiers that are disabled."
                     },
                     },
                     {
                     {
@@ -1407,7 +1407,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of the function that is triggered when a menu option is selected.<br/><br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: List where the first element contains the id of the selected option.</li>\n</ul>\n</li>\n</ul>",
+                        "doc": "The name of the function that is triggered when a menu option is selected.<br/><br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button if it has one.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: List where the first element contains the id of the selected option.</li>\n</ul>\n</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1453,7 +1453,7 @@
                     {
                     {
                         "name": "value",
                         "name": "value",
                         "default_property": true,
                         "default_property": true,
-                        "type": "tuple|dict|list[dict]|list[tuple]",
+                        "type": "Union[tuple,dict,list[dict],list[tuple]]",
                         "doc": "The different status items to represent. See below."
                         "doc": "The different status items to represent. See below."
                     },
                     },
                     {
                     {
@@ -1482,7 +1482,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of the function that is triggered when the dialog button is pressed.<br/><br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: a list with three elements:\n<ul><li>The first element is the username</li><li>The second element is the password</li><li>The third element is the current page name</li></ul></li></li>\n</ul>\n</li>\n</ul><br/>When the button is pressed, and if this property is not set, Taipy will try to find a callback function called <i>on_login()</i> and invoke it with the parameters listed above.",
+                        "doc": "The name of the function that is triggered when the dialog button is pressed.<br/><br/>All the parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str): the identifier of the button if it has one.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: a list with three elements:\n<ul><li>The first element is the username</li><li>The second element is the password</li><li>The third element is the current page name</li></ul></li></li>\n</ul>\n</li>\n</ul><br/>When the button is pressed, and if this property is not set, Taipy will try to find a callback function called <i>on_login()</i> and invoke it with the parameters listed above.",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1523,7 +1523,7 @@
                     },
                     },
                     {
                     {
                         "name": "users",
                         "name": "users",
-                        "type": "dynamic(list[str|Icon])",
+                        "type": "dynamic(list[Union[str,Icon]])",
                         "doc": "The list of users. See the <a href=\"../../binding/#list-of-values\">section on List of Values</a> for details."
                         "doc": "The list of users. See the <a href=\"../../binding/#list-of-values\">section on List of Values</a> for details."
                     },
                     },
                     {
                     {
@@ -1565,7 +1565,7 @@
                     },
                     },
                     {
                     {
                         "name": "height",
                         "name": "height",
-                        "type": "str|int|float",
+                        "type": "Union[str,int,float]",
                         "doc": "The maximum height of this chat control, in CSS units."
                         "doc": "The maximum height of this chat control, in CSS units."
                     }
                     }
                 ]
                 ]
@@ -1580,7 +1580,7 @@
                 "properties": [
                 "properties": [
                     {
                     {
                         "name": "expanded",
                         "name": "expanded",
-                        "type": "dynamic(bool|str[])",
+                        "type": "dynamic(Union[bool,list[str]])",
                         "default_value": "True",
                         "default_value": "True",
                         "doc": "If Boolean and False, only one node can be expanded at one given level. Otherwise this should be set to an array of the node identifiers that need to be expanded."
                         "doc": "If Boolean and False, only one node can be expanded at one given level. Otherwise this should be set to an array of the node identifiers that need to be expanded."
                     },
                     },
@@ -1687,7 +1687,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "Name of a function triggered when a button 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 identifier of the dialog.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: a list where the first element contains the index of the selected label.</li>\n</ul>\n</li>\n</ul>",
+                        "doc": "Name of a function triggered when a button 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 identifier of the dialog if it has one.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args: a list where the first element contains the index of the selected label.</li>\n</ul>\n</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1711,17 +1711,17 @@
                     },
                     },
                     {
                     {
                         "name": "labels",
                         "name": "labels",
-                        "type": " str|list[str]",
+                        "type": "Union[str,list[str]]",
                         "doc": "A list of labels to show in a row of buttons at the bottom of the dialog. The index of the button in the list is reported as args in the <tt>on_action</tt> callback (that index is -1 for the <i>close</i> icon)."
                         "doc": "A list of labels to show in a row of buttons at the bottom of the dialog. The index of the button in the list is reported as args in the <tt>on_action</tt> callback (that index is -1 for the <i>close</i> icon)."
                     },
                     },
                     {
                     {
                         "name": "width",
                         "name": "width",
-                        "type": "str|int|float",
+                        "type": "Union[str,int,float]",
                         "doc": "The width of this dialog, in CSS units."
                         "doc": "The width of this dialog, in CSS units."
                     },
                     },
                     {
                     {
                         "name": "height",
                         "name": "height",
-                        "type": "str|int|float",
+                        "type": "Union[str,int,float]",
                         "doc": "The height of this dialog, in CSS units."
                         "doc": "The height of this dialog, in CSS units."
                     }
                     }
                 ]
                 ]
@@ -1776,7 +1776,7 @@
                     {
                     {
                         "name": "on_close",
                         "name": "on_close",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "The name of a function that is triggered when this pane is closed (if the user clicks outside of it or presses the Esc key).<br/>All parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (str|None): the identifier of the button.</li>\n</ul><br/>If this property is not set, no function is called when this pane is closed.",
+                        "doc": "The name of a function that is triggered when this pane is closed (if the user clicks outside of it or presses the Esc key).<br/>All parameters of that function are optional:\n<ul>\n<li>state (<code>State^</code>): the state instance.</li>\n<li>id (optional[str]): the identifier of the close button if it has one.</li>\n</ul><br/>If this property is not set, no function is called when this pane is closed.",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1852,7 +1852,7 @@
                         "name": "adapter",
                         "name": "adapter",
                         "type": "Function",
                         "type": "Function",
                         "default_value": "`lambda x: str(x)`",
                         "default_value": "`lambda x: str(x)`",
-                        "doc": "The function that transforms an element of <i>lov</i> into a <i>tuple(id:str, label:str|Icon)</i>."
+                        "doc": "The function that transforms an element of <i>lov</i> into a <i>tuple(id:str, label:Union[str,Icon])</i>."
                     },
                     },
                     {
                     {
                         "name": "type",
                         "name": "type",
@@ -1901,7 +1901,7 @@
                 "properties": [
                 "properties": [
                     {
                     {
                         "name": "partial",
                         "name": "partial",
-                        "type": "Partial",
+                        "type": "taipy.gui.Partial",
                         "doc": "A Partial object that holds the content of the block.<br/>This should not be defined if <i>page</i> is set."
                         "doc": "A Partial object that holds the content of the block.<br/>This should not be defined if <i>page</i> is set."
                     },
                     },
                     {
                     {
@@ -1942,7 +1942,7 @@
                     {
                     {
                         "name": "on_action",
                         "name": "on_action",
                         "type": "Callback",
                         "type": "Callback",
-                        "doc": "Name of a function that is triggered when a specific key 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 identifier of the input.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args (list):\n<ul><li>key name</li><li>variable name</li><li>current value</li></ul>\n</li>\n</ul>\n</li>\n</ul>",
+                        "doc": "Name of a function that is triggered when a specific key 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 identifier of the control if it has one.</li>\n<li>payload (dict): the details on this callback's invocation.<br/>\nThis dictionary has the following keys:\n<ul>\n<li>action: the name of the action that triggered this callback.</li>\n<li>args (list):\n<ul><li>key name</li><li>variable name</li><li>current value</li></ul>\n</li>\n</ul>\n</li>\n</ul>",
                         "signature": [
                         "signature": [
                             [
                             [
                                 "state",
                                 "state",
@@ -1974,25 +1974,21 @@
                     {
                     {
                         "name": "id",
                         "name": "id",
                         "type": "str",
                         "type": "str",
-                        "default_value": "None",
                         "doc": "The identifier that is assigned to the rendered HTML component."
                         "doc": "The identifier that is assigned to the rendered HTML component."
                     },
                     },
                     {
                     {
                         "name": "properties",
                         "name": "properties",
                         "type": "dict[str, any]",
                         "type": "dict[str, any]",
-                        "default_value": "None",
                         "doc": "Bound to a dictionary that contains additional properties for this element."
                         "doc": "Bound to a dictionary that contains additional properties for this element."
                     },
                     },
                     {
                     {
                         "name": "class_name",
                         "name": "class_name",
                         "type": "dynamic(str)",
                         "type": "dynamic(str)",
-                        "default_value": "None",
                         "doc": "The list of CSS class names that are associated with the generated HTML Element.<br/>These class names are added to the default <code>taipy-&lt;element_type&gt;</code> class name."
                         "doc": "The list of CSS class names that are associated with the generated HTML Element.<br/>These class names are added to the default <code>taipy-&lt;element_type&gt;</code> class name."
                     },
                     },
                     {
                     {
                         "name": "hover_text",
                         "name": "hover_text",
                         "type": "dynamic(str)",
                         "type": "dynamic(str)",
-                        "default_value": "None",
                         "doc": "The information that is displayed when the user hovers over this element."
                         "doc": "The information that is displayed when the user hovers over this element."
                     }
                     }
                 ]
                 ]

+ 0 - 8
tools/gui/builder/block.txt

@@ -1,8 +0,0 @@
-
-class {{name}}(_Block):
-    _ELEMENT_NAME: str
-    def __init__(self, {{properties}}) -> None:
-        """### Arguments:
-{{doc_arguments}}
-        """
-        ...

+ 0 - 8
tools/gui/builder/control.txt

@@ -1,8 +0,0 @@
-
-class {{name}}(_Control):
-    _ELEMENT_NAME: str
-    def __init__(self, {{properties}}) -> None:
-        """### Arguments:
-{{doc_arguments}}
-        """
-        ...

+ 125 - 93
tools/gui/generate_pyi.py

@@ -12,24 +12,25 @@
 import json
 import json
 import os
 import os
 import re
 import re
-import typing as t
+import sys
 
 
 from markdownify import markdownify
 from markdownify import markdownify
 
 
-# ############################################################
-# Generate Python interface definition files
-# ############################################################
-from taipy.gui.config import Config
+# Make sure we can import the mandatory packages
+script_dir = os.path.dirname(os.path.realpath(__file__))
+if not os.path.isdir(os.path.abspath(os.path.join(script_dir, "taipy"))):
+    sys.path.append(os.path.abspath(os.path.join(script_dir, os.pardir, os.pardir)))
 
 
-# ############################################################
+# ##################################################################################################
 # Generate gui pyi file (gui/gui.pyi)
 # Generate gui pyi file (gui/gui.pyi)
-# ############################################################
+# ##################################################################################################
 gui_py_file = "./taipy/gui/gui.py"
 gui_py_file = "./taipy/gui/gui.py"
-gui_pyi_file = gui_py_file + "i"
+gui_pyi_file = f"{gui_py_file}i"
+from taipy.config import Config  # noqa: E402
 
 
+# Generate Python interface definition files
 os.system(f"pipenv run stubgen {gui_py_file} --no-import --parse-only --export-less -o ./")
 os.system(f"pipenv run stubgen {gui_py_file} --no-import --parse-only --export-less -o ./")
 
 
-
 gui_config = "".join(
 gui_config = "".join(
     f", {k}: {v.__name__} = ..."
     f", {k}: {v.__name__} = ..."
     if "<class" in str(v)
     if "<class" in str(v)
@@ -44,14 +45,15 @@ with open(gui_pyi_file, "r") as file:
             replace_str = line[line.index(", run_server") : (line.index("**kwargs") + len("**kwargs"))]
             replace_str = line[line.index(", run_server") : (line.index("**kwargs") + len("**kwargs"))]
             # ", run_server: bool = ..., run_in_thread: bool = ..., async_mode: str = ..., **kwargs"
             # ", run_server: bool = ..., run_in_thread: bool = ..., async_mode: str = ..., **kwargs"
             line = line.replace(replace_str, gui_config)
             line = line.replace(replace_str, gui_config)
-        replaced_content = replaced_content + line
+        replaced_content += line
 
 
 with open(gui_pyi_file, "w") as write_file:
 with open(gui_pyi_file, "w") as write_file:
     write_file.write(replaced_content)
     write_file.write(replaced_content)
 
 
-# ################
+# ##################################################################################################
+# Generate Page Builder pyi file (gui/builder/__init__.pyi)
+# ##################################################################################################
 # Read the version
 # Read the version
-# ################
 current_version = "latest"
 current_version = "latest"
 with open("./taipy/gui/version.json", "r") as vfile:
 with open("./taipy/gui/version.json", "r") as vfile:
     version = json.load(vfile)
     version = json.load(vfile)
@@ -59,108 +61,138 @@ with open("./taipy/gui/version.json", "r") as vfile:
         current_version = "develop"
         current_version = "develop"
     else:
     else:
         current_version = f'release-{version.get("major", 0)}.{version.get("minor", 0)}'
         current_version = f'release-{version.get("major", 0)}.{version.get("minor", 0)}'
-taipy_doc_url = f"https://docs.taipy.io/en/{current_version}/manuals/userman/gui/viselements/generic/"
 
 
+taipy_doc_url = f"https://docs.taipy.io/en/{current_version}/manuals/userman/gui/viselements/generic/"
 
 
-# ############################################################
-# Generate Page Builder pyi file (gui/builder/__init__.pyi)
-# ############################################################
 builder_py_file = "./taipy/gui/builder/__init__.py"
 builder_py_file = "./taipy/gui/builder/__init__.py"
-builder_pyi_file = builder_py_file + "i"
+builder_pyi_file = f"{builder_py_file}i"
 with open("./taipy/gui/viselements.json", "r") as file:
 with open("./taipy/gui/viselements.json", "r") as file:
     viselements = json.load(file)
     viselements = json.load(file)
-with open("./tools/gui/builder/block.txt", "r") as file:
-    block_template = file.read()
-with open("./tools/gui/builder/control.txt", "r") as file:
-    control_template = file.read()
-
 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 ._element import _Element, _Block, _Control\n")
+    file.write("from typing import Union\n")
+    file.write("\n")
+    file.write("from ._element import _Block, _Control, _Element\n")
 
 
 
 
-def get_properties(element, viselements) -> t.List[t.Dict[str, t.Any]]:
-    properties = element["properties"]
-    if "inherits" not in element:
+def resolve_inherit(name: str, properties, inherits, viselements) -> list[dict[str, any]]:
+    if not inherits:
         return properties
         return properties
-    for inherit in element["inherits"]:
-        inherit_element = next((e for e in viselements["undocumented"] if e[0] == inherit), None)
-        if inherit_element is None:
-            inherit_element = next((e for e in viselements["blocks"] if e[0] == inherit), None)
-        if inherit_element is None:
-            inherit_element = next((e for e in viselements["controls"] if e[0] == inherit), None)
-        if inherit_element is None:
-            raise RuntimeError(f"Can't find element with name {inherit}")
-        properties += get_properties(inherit_element[1], viselements)
+    for inherit_name in inherits:
+        inherited_desc = next((e for e in viselements["undocumented"] if e[0] == inherit_name), None)
+        if inherited_desc is None:
+            inherited_desc = next((e for e in viselements["blocks"] if e[0] == inherit_name), None)
+        if inherited_desc is None:
+            inherited_desc = next((e for e in viselements["controls"] if e[0] == inherit_name), None)
+        if inherited_desc is None:
+            raise RuntimeError(f"Element type '{name}' inherits from unknown element type '{inherit_name}'")
+        inherited_desc = inherited_desc[1]
+        for inherit_prop in inherited_desc["properties"]:
+            prop_desc = next((p for p in properties if p["name"] == inherit_prop["name"]), None)
+            if prop_desc: # Property exists
+                def override(current, inherits, p: str):
+                    if p not in current and (inherited := inherits.get(p, None)):
+                        current[p] = inherited
+                override(prop_desc, inherit_prop, "type")
+                override(prop_desc, inherit_prop, "default_value")
+                override(prop_desc, inherit_prop, "doc")
+                override(prop_desc, inherit_prop, "signature")
+            else:
+                properties.append(inherit_prop)
+            properties =  resolve_inherit(inherit_name, properties, inherited_desc.get("inherits", None), viselements)
     return properties
     return properties
 
 
+def format_as_parameter(property):
+    type = property["type"]
+    if m := re.match(r"indexed\((.*)\)", type):
+        type = m[1]
+        property["indexed"] = " (indexed)"
+    else:
+        property["indexed"] = ""
+    if m := re.match(r"dynamic\((.*)\)", type):
+        type = m[1]
+        property["dynamic"] = " (dynamic)"
+    else:
+        property["dynamic"] = ""
+    if type == "Callback" or type == "Function":
+        type = ""
+    else:
+        type = f": {type}"
+    default_value = property.get("default_value", None)
+    if default_value is not None:
+        try:
+            eval(default_value)
+            default_value = f" = {default_value}"
+        except Exception:
+            default_value = ""
+    else:
+        default_value = ""
+    return f"{property['name']}{type}{default_value}"
 
 
-def build_doc(name: str, element: t.Dict[str, t.Any]):
-    if "doc" not in element:
+def build_doc(name: str, desc: dict[str, any]):
+    if "doc" not in desc:
         return ""
         return ""
-    doc = str(element["doc"]).replace("\n", f'\n{16*" "}')
-    doc = re.sub(
-        r"^(.*\..*\shref=\")([^h].*)(\".*\..*)$",
-        r"\1" + taipy_doc_url + name + r"/\2\3",
-        doc,
-    )
-    doc = re.sub(
-        r"^(.*\.)(<br/>|\s)(See below((?!href=).)*\.)(.*)$",
-        r"\1\3",
-        doc,
-    )
-    doc = markdownify(doc, strip=["br"])
-    return f"{element['name']} ({element['type']}): {doc} {'(default: '+markdownify(element['default_value']) + ')' if 'default_value' in element else ''}"  # noqa: E501
-
-
-for control_element in viselements["controls"]:
-    name = control_element[0]
-    property_list: t.List[t.Dict[str, t.Any]] = []
-    property_names: t.List[str] = []
-    hidden_properties: t.List[str] = []
-    for property in get_properties(control_element[1], viselements):
-        if "hide" in property and property["hide"] is True:
-            hidden_properties.append(property["name"])
-            continue
-        if (
-            property["name"] not in property_names
-            and "[" not in property["name"]
-            and property["name"] not in hidden_properties
-        ):
+    doc = desc["doc"]
+    if desc["name"] == "class_name":
+        doc = doc.replace("<element_type>", name)
+    # This won't work for Scenartio Management and Block elements
+    doc = re.sub(r"(href=\")\.\.((?:.*?)\")", r"\1" + taipy_doc_url + name + r"/../..\2", doc)
+    doc = "\n  ".join(markdownify(doc).split("\n"))
+    doc = doc.replace("  \n", "  \\n")
+    doc = re.sub(r"(?:\s+\\n)?\s+See below(?:[^\.]*)?\.", "", doc).replace("\n", "\\n")
+    return f"{desc['name']}{desc['dynamic']}{desc['indexed']}\\n  {doc}\\n\\n"
+
+
+element_template = """
+
+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
+        ...
+"""
+
+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 and indexed properties (TODO?)
+        properties = [p for p in properties if not p.get("hide", False) and "[" not in p["name"]]
+        # 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:
             if "default_property" in property and property["default_property"] is True:
                 property_list.insert(0, property)
                 property_list.insert(0, property)
                 property_names.insert(0, property["name"])
                 property_names.insert(0, property["name"])
                 continue
                 continue
             property_list.append(property)
             property_list.append(property)
             property_names.append(property["name"])
             property_names.append(property["name"])
-    properties = ", ".join([f"{p} = ..." for p in property_names if p not in hidden_properties])
-    doc_arguments = "\n".join([build_doc(name, p) for p in property_list if p["name"] not in hidden_properties])
-    # append properties to __init__.pyi
-    with open(builder_pyi_file, "a") as file:
-        file.write(
-            control_template.replace("{{name}}", name)
-            .replace("{{properties}}", properties)
-            .replace("{{doc_arguments}}", doc_arguments)
-        )
-
-for block_element in viselements["blocks"]:
-    name = block_element[0]
-    property_list = []
-    property_names = []
-    for property in get_properties(block_element[1], viselements):
-        if property["name"] not in property_names and "[" not in property["name"]:
-            property_list.append(property)
-            property_names.append(property["name"])
-    properties = ", ".join([f"{p} = ..." for p in property_names])
-    doc_arguments = "\n".join([build_doc(name, p) for p in property_list])
-    # append properties to __init__.pyi
-    with open(builder_pyi_file, "a") as file:
-        file.write(
-            block_template.replace("{{name}}", name)
-            .replace("{{properties}}", properties)
-            .replace("{{doc_arguments}}", doc_arguments)
-        )
+        # 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)
+            )
+
+
+
+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}")