Просмотр исходного кода

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

* Json Resolver

* per Fabien and Fred

* fix linter
Dinh Long Nguyen 1 год назад
Родитель
Сommit
2ad505763e
2 измененных файлов с 45 добавлено и 22 удалено
  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 ._init import *
 from ._renderers import Html, Markdown
 from ._renderers import Html, Markdown
+from ._renderers.json import JsonAdapter
 from .gui_actions import (
 from .gui_actions import (
     broadcast_callback,
     broadcast_callback,
     download,
     download,

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

@@ -10,45 +10,67 @@
 # specific language governing permissions and limitations under the License.
 # specific language governing permissions and limitations under the License.
 from __future__ import annotations
 from __future__ import annotations
 
 
+import typing as t
+from abc import ABC, abstractmethod
 from datetime import date, datetime, time
 from datetime import date, datetime, time
 from json import JSONEncoder
 from json import JSONEncoder
 from pathlib import Path
 from pathlib import Path
-from types import FunctionType, LambdaType
 
 
 from flask.json.provider import DefaultJSONProvider
 from flask.json.provider import DefaultJSONProvider
 
 
 from .._warnings import _warn
 from .._warnings import _warn
 from ..icon import Icon
 from ..icon import Icon
 from ..utils import _date_to_string, _MapDict, _TaipyBase
 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
         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):
 class _TaipyJsonEncoder(JSONEncoder):
     def default(self, o):
     def default(self, o):
-        return _default(o)
+        return _TaipyJsonAdapter().parse(o)
 
 
 
 
 class _TaipyJsonProvider(DefaultJSONProvider):
 class _TaipyJsonProvider(DefaultJSONProvider):
-    default = staticmethod(_default)  # type: ignore
+    default = staticmethod(_TaipyJsonAdapter().parse)  # type: ignore
     sort_keys = False
     sort_keys = False