Browse Source

GUI: Json Resolver (#826) (#864)

* Json Resolver

* per Fabien and Fred

* fix linter
Dinh Long Nguyen 1 year ago
parent
commit
2ad505763e
2 changed files with 45 additions and 22 deletions
  1. 1 0
      taipy/gui/__init__.py
  2. 44 22
      taipy/gui/_renderers/json.py

+ 1 - 0
taipy/gui/__init__.py

@@ -72,6 +72,7 @@ from importlib.util import find_spec
 
 from ._init import *
 from ._renderers import Html, Markdown
+from ._renderers.json import JsonAdapter
 from .gui_actions import (
     broadcast_callback,
     download,

+ 44 - 22
taipy/gui/_renderers/json.py

@@ -10,45 +10,67 @@
 # specific language governing permissions and limitations under the License.
 from __future__ import annotations
 
+import typing as t
+from abc import ABC, abstractmethod
 from datetime import date, datetime, time
 from json import JSONEncoder
 from pathlib import Path
-from types import FunctionType, LambdaType
 
 from flask.json.provider import DefaultJSONProvider
 
 from .._warnings import _warn
 from ..icon import Icon
 from ..utils import _date_to_string, _MapDict, _TaipyBase
+from ..utils.singleton import _Singleton
 
 
-def _default(o):
-    if isinstance(o, Icon):
-        return o._to_dict()
-    if isinstance(o, _MapDict):
-        return o._dict
-    if isinstance(o, _TaipyBase):
-        return o.get()
-    if isinstance(o, (datetime, date, time)):
-        return _date_to_string(o)
-    if isinstance(o, Path):
-        return str(o)
-    if isinstance(o, FunctionType):
-        return o.__name__
-    if isinstance(o, LambdaType):
-        return str(o)
-    try:
-        raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")
-    except Exception as e:
-        _warn("Exception in JSONEncoder", e)
+class JsonAdapter(ABC):
+    def register(self):
+        _TaipyJsonAdapter().register(self)
+
+    @abstractmethod
+    def parse(self, o) -> t.Union[t.Any, None]:
         return None
 
 
+class _DefaultJsonAdapter(JsonAdapter):
+    def parse(self, o):
+        if isinstance(o, Icon):
+            return o._to_dict()
+        if isinstance(o, _MapDict):
+            return o._dict
+        if isinstance(o, _TaipyBase):
+            return o.get()
+        if isinstance(o, (datetime, date, time)):
+            return _date_to_string(o)
+        if isinstance(o, Path):
+            return str(o)
+
+
+class _TaipyJsonAdapter(object, metaclass=_Singleton):
+    def __init__(self):
+        self._adapters: t.List[JsonAdapter] = []
+        self.register(_DefaultJsonAdapter())
+
+    def register(self, adapter: JsonAdapter):
+        self._adapters.append(adapter)
+
+    def parse(self, o):
+        try:
+            for adapter in reversed(self._adapters):
+                if (output := adapter.parse(o)) is not None:
+                    return output
+            raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")
+        except Exception as e:
+            _warn("Exception while resolving JSON", e)
+            return None
+
+
 class _TaipyJsonEncoder(JSONEncoder):
     def default(self, o):
-        return _default(o)
+        return _TaipyJsonAdapter().parse(o)
 
 
 class _TaipyJsonProvider(DefaultJSONProvider):
-    default = staticmethod(_default)  # type: ignore
+    default = staticmethod(_TaipyJsonAdapter().parse)  # type: ignore
     sort_keys = False