Skip to content

Commit

Permalink
Merge branch 'develop' into test/Table
Browse files Browse the repository at this point in the history
  • Loading branch information
namnguyen20999 authored Aug 2, 2024
2 parents 67bc921 + f156ec4 commit 698fa36
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/overall-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
uses: ./.github/workflows/partial-tests.yml

coverage:
timeout-minutes: 40
timeout-minutes: 50
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion taipy/gui/builder/_api_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def add_library(self, library: "ElementLibrary"):
)
# Allow element to be accessed from the root module
if hasattr(self.__module, element_name):
_TaipyLogger()._get_logger().info(
_TaipyLogger._get_logger().info(
f"Can't add element `{element_name}` of library `{library_name}` to the root of Builder API as another element with the same name already exists." # noqa: E501
)
continue
Expand Down
24 changes: 20 additions & 4 deletions taipy/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
from .data.data_format import _DataFormat
from .data.data_scope import _DataScopes
from .extension.library import Element, ElementLibrary
from .hook import Hooks
from .page import Page
from .partial import Partial
from .server import _Server
Expand Down Expand Up @@ -365,6 +366,9 @@ def __init__(
]
)

# Init Gui Hooks
Hooks()._init(self)

if page:
self.add_page(name=Gui.__root_page_name, page=page)
if pages is not None:
Expand Down Expand Up @@ -603,10 +607,10 @@ def __clean_vars_on_exit(self) -> t.Optional[t.Set[str]]:
return None

def _handle_connect(self):
pass
Hooks().handle_connect(self)

def _handle_disconnect(self):
pass
Hooks()._handle_disconnect(self)

def _manage_message(self, msg_type: _WsType, message: dict) -> None:
try:
Expand Down Expand Up @@ -667,7 +671,7 @@ def _manage_message(self, msg_type: _WsType, message: dict) -> None:
# To be expanded by inheriting classes
# this will be used to handle ws messages that is not handled by the base Gui class
def _manage_external_message(self, msg_type: _WsType, message: dict) -> None:
pass
Hooks()._manage_external_message(self, msg_type, message)

def __front_end_update(
self,
Expand Down Expand Up @@ -1900,6 +1904,8 @@ def add_page(
# set root page
if name == Gui.__root_page_name:
self._config.root_page = new_page
# Validate Page
Hooks().validate_page(self, page)
# Update locals context
self.__locals_context.add(page._get_module_name(), page._get_locals())
# Update variable directory
Expand All @@ -1909,6 +1915,8 @@ def add_page(
if _is_in_notebook():
page._notebook_gui = self
page._notebook_page = new_page
# add page to hook
Hooks().add_page(self, page)

def add_pages(self, pages: t.Optional[t.Union[t.Mapping[str, t.Union[str, Page]], str]] = None) -> None:
"""Add several pages to the Graphical User Interface.
Expand Down Expand Up @@ -2366,12 +2374,16 @@ def _set_frame(self, frame: t.Optional[FrameType]):
self.__default_module_name = _get_module_name_from_frame(self.__frame)

def _set_css_file(self, css_file: t.Optional[str] = None):
script_file = Path(self.__frame.f_code.co_filename or ".").resolve()
if css_file is None:
script_file = Path(self.__frame.f_code.co_filename or ".").resolve()
if script_file.with_suffix(".css").exists():
css_file = f"{script_file.stem}.css"
elif script_file.is_dir() and (script_file / "taipy.css").exists():
css_file = "taipy.css"
if css_file is None:
script_file = script_file.with_name("taipy").with_suffix(".css")
if script_file.exists():
css_file = f"{script_file.stem}.css"
self.__css_file = css_file

def _set_state(self, state: State):
Expand Down Expand Up @@ -2620,6 +2632,10 @@ def run(
#
# The default value is None.
# --------------------------------------------------------------------------------

# setup run function with gui hooks
Hooks().run(self, **kwargs)

app_config = self._config.config

run_root_dir = os.path.dirname(inspect.getabsfile(self.__frame))
Expand Down
45 changes: 45 additions & 0 deletions taipy/gui/hook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import typing as t

from taipy.logger._taipy_logger import _TaipyLogger

from .utils.singleton import _Singleton


class Hook:
method_names: t.List[str] = []


class Hooks(object, metaclass=_Singleton):
def __init__(self):
self.__hooks: t.List[Hook] = []

Check failure on line 14 in taipy/gui/hook.py

View workflow job for this annotation

GitHub Actions / partial-tests / linter

By default the bodies of untyped functions are not checked, consider using --check-untyped-defs [annotation-unchecked]

def _register_hook(self, hook: Hook):
# Prevent duplicated hooks
for h in self.__hooks:
if type(hook) is type(h):
_TaipyLogger._get_logger().info(f"Failed to register duplicated hook of type '{type(h)}'")
return
self.__hooks.append(hook)

def __getattr__(self, name: str):
def _resolve_hook(*args, **kwargs):
for hook in self.__hooks:
if name not in hook.method_names:
continue
# call hook
try:
func = getattr(hook, name)
if not callable(func):
raise Exception(f"'{name}' hook is not callable")
res = getattr(hook, name)(*args, **kwargs)
except Exception as e:
_TaipyLogger._get_logger().error(f"Error while calling hook '{name}': {e}")
return
# check if the hook returns True -> stop the chain
if res is True:
return
# only hooks that return true are allowed to return values to ensure consistent response
if isinstance(res, (list, tuple)) and len(res) == 2 and res[0] is True:
return res[1]

return _resolve_hook
4 changes: 2 additions & 2 deletions taipy/gui/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def __getattribute__(self, name: str) -> t.Any:
name not in gui._get_shared_variables() and not gui._bindings()._is_single_client()
):
raise AttributeError(f"Variable '{name}' is not available to be accessed in shared callback.")
if name not in super().__getattribute__(State.__attrs[1]):
if not name.startswith("__") and name not in super().__getattribute__(State.__attrs[1]):
raise AttributeError(f"Variable '{name}' is not defined.")
with self._notebook_context(gui), self._set_context(gui):
encoded_name = gui._bind_var(name)
Expand All @@ -140,7 +140,7 @@ def __setattr__(self, name: str, value: t.Any) -> None:
name not in gui._get_shared_variables() and not gui._bindings()._is_single_client()
):
raise AttributeError(f"Variable '{name}' is not available to be accessed in shared callback.")
if name not in super().__getattribute__(State.__attrs[1]):
if not name.startswith("__") and name not in super().__getattribute__(State.__attrs[1]):
raise AttributeError(f"Variable '{name}' is not accessible.")
with self._notebook_context(gui), self._set_context(gui):
encoded_name = gui._bind_var(name)
Expand Down
6 changes: 3 additions & 3 deletions taipy/gui/viselements.json
Original file line number Diff line number Diff line change
Expand Up @@ -1264,7 +1264,7 @@
"name": "value",
"type": "dynamic(int)",
"doc": "If set, then the value represents the progress percentage that is shown.TODO - if unset?",
"default_property": "true"
"default_property": true
},
{
"name": "linear",
Expand All @@ -1281,8 +1281,8 @@
{
"name": "render",
"type": "dynamic(bool)",
"doc": "If False, this progress indicator is hidden from the page.",
"default_property": "true"
"default_value": "True",
"doc": "If False, this progress indicator is hidden from the page."
}
]
}
Expand Down
Loading

0 comments on commit 698fa36

Please sign in to comment.