Ver Fonte

improve exception reporting in expressions (#2156)

* improve exception reporting in expressions
resolves #2144

* linter

* fix test

* better fix test

---------

Co-authored-by: Fred Lefévère-Laoide <Fred.Lefevere-Laoide@Taipy.io>
Fred Lefévère-Laoide há 6 meses atrás
pai
commit
5e58fd16cf

+ 11 - 1
taipy/gui/_page.py

@@ -17,6 +17,8 @@ import re
 import typing as t
 import warnings
 
+from ._warnings import TaipyGuiAlwaysWarning
+
 if t.TYPE_CHECKING:
     from ._renderers import Page
     from .gui import Gui
@@ -40,7 +42,15 @@ class _Page(object):
             warnings.resetwarnings()
             with gui._set_locals_context(self._renderer._get_module_name()):
                 self._rendered_jsx = self._renderer.render(gui)
-            if not silent:
+            if silent:
+                s = ""
+                for wm in w:
+                    if wm.category is TaipyGuiAlwaysWarning:
+                        s += f" - {wm.message}\n"
+                if s:
+                    logging.warning("\033[1;31m\n" + s)
+
+            else:
                 if (
                     self._rendered_jsx
                     and isinstance(self._rendered_jsx, str)

+ 13 - 4
taipy/gui/_warnings.py

@@ -30,15 +30,24 @@ class TaipyGuiWarning(UserWarning):
         )
 
 
-def _warn(message: str, e: t.Optional[BaseException] = None):
+class TaipyGuiAlwaysWarning(TaipyGuiWarning):
+    pass
+
+
+def _warn(
+    message: str,
+    e: t.Optional[BaseException] = None,
+    always_show: t.Optional[bool] = False,
+):
     warnings.warn(
         (
-            f"{message}:\n{''.join(traceback.format_exception(type(e), e, e.__traceback__))}"
+            f"{message}:\n{''.join(traceback.format_exception(e))}"
             if e and TaipyGuiWarning._tp_debug_mode
-            else f"{message}:\n{e}"
+            else f"{message}:\n"
+            + "".join(traceback.format_exception(None, e, e.__traceback__.tb_next if e.__traceback__ else None))
             if e
             else message
         ),
-        TaipyGuiWarning,
+        TaipyGuiWarning if not always_show else TaipyGuiAlwaysWarning,
         stacklevel=2,
     )

+ 13 - 3
taipy/gui/utils/_evaluator.py

@@ -47,6 +47,7 @@ class _Evaluator:
     __EXPR_EDGE_CASE_F_STRING = re.compile(r"[\{]*[a-zA-Z_][a-zA-Z0-9_]*:.+")
     __IS_TAIPY_EXPR_RE = re.compile(r"TpExPr_(.*)")
     __IS_ARRAY_EXPR_RE = re.compile(r"[^[]*\[(\d+)][^]]*")
+    __CLEAN_LAMBDA_RE = re.compile(r"^__lambda_[\d_]+(TPMDL_\d+)?(.*)$")
 
     def __init__(self, default_bindings: t.Dict[str, t.Any], shared_variable: t.List[str]) -> None:
         # key = expression, value = hashed value of the expression
@@ -260,7 +261,12 @@ class _Evaluator:
             with gui._get_authorization():
                 expr_evaluated = eval(not_encoded_expr if is_edge_case else expr_string, ctx)
         except Exception as e:
-            _warn(f"Cannot evaluate expression '{not_encoded_expr if is_edge_case else expr_string}'", e)
+            exception_str = not_encoded_expr if is_edge_case else expr_string
+            _warn(
+                f"Cannot evaluate expression '{_Evaluator._clean_exception_expr(exception_str)}'",
+                e,
+                always_show=True,
+            )
             expr_evaluated = None
         if lambda_expr and callable(expr_evaluated):
             expr_hash = _get_lambda_id(expr_evaluated, module=module_name)  # type: ignore[reportArgumentType]
@@ -291,7 +297,7 @@ class _Evaluator:
             if holder is not None:
                 holder.set(expr_evaluated)
         except Exception as e:
-            _warn(f"Exception raised evaluating {expr_string}", e)
+            _warn(f"Exception raised evaluating {_Evaluator._clean_exception_expr(expr_string)}", e)
 
     def re_evaluate_expr(self, gui: Gui, var_name: str) -> t.Set[str]:  # noqa C901
         """
@@ -366,7 +372,7 @@ class _Evaluator:
                         expr_evaluated = eval(expr_string, ctx)
                         _setscopeattr(gui, hash_expr, expr_evaluated)
                     except Exception as e:
-                        _warn(f"Exception raised evaluating {expr_string}", e)
+                        _warn(f"Exception raised evaluating {_Evaluator._clean_exception_expr(expr_string)}", e)
             # refresh holders if any
             for h in self.__expr_to_holders.get(expr, []):
                 holder_hash = self.__get_holder_hash(h, self.get_hash_from_expr(expr))
@@ -378,3 +384,7 @@ class _Evaluator:
 
     def _get_instance_in_context(self, name: str):
         return self.__global_ctx.get(name)
+
+    @staticmethod
+    def _clean_exception_expr(expr: str):
+        return _Evaluator.__CLEAN_LAMBDA_RE.sub(r"<lambda>\2", expr)

+ 1 - 1
tests/gui/helpers.py

@@ -165,4 +165,4 @@ class Helpers:
 
     @staticmethod
     def get_taipy_warnings(warns: t.List[warnings.WarningMessage]) -> t.List[warnings.WarningMessage]:
-        return [w for w in warns if w.category is TaipyGuiWarning]
+        return [w for w in warns if issubclass(w.category, TaipyGuiWarning)]

+ 1 - 1
tools/release/bump_version.py

@@ -93,5 +93,5 @@ if __name__ == "__main__":
     for _path in paths:
         _version = extract_version(_path)
         bump_ext_version(_version, _path)
-    print(f"NEW_VERSION={_version.dev_name}")
+    print(f"NEW_VERSION={_version.dev_name}") # noqa T201 # type: ignore[reportPossiblyUnboundVariable]