data_accessor.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. # Copyright 2021-2024 Avaiga Private Limited
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  4. # the License. You may obtain a copy of the License at
  5. #
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. #
  8. # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  9. # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  10. # specific language governing permissions and limitations under the License.
  11. import inspect
  12. import typing as t
  13. from abc import ABC, abstractmethod
  14. from .._warnings import _warn
  15. from ..utils import _TaipyData
  16. from .data_format import _DataFormat
  17. class _DataAccessor(ABC):
  18. _WS_DATE_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
  19. @staticmethod
  20. @abstractmethod
  21. def get_supported_classes() -> t.List[str]:
  22. pass
  23. @abstractmethod
  24. def get_data(
  25. self, guiApp: t.Any, var_name: str, value: t.Any, payload: t.Dict[str, t.Any], data_format: _DataFormat
  26. ) -> t.Dict[str, t.Any]:
  27. pass
  28. @abstractmethod
  29. def get_col_types(self, var_name: str, value: t.Any) -> t.Dict[str, str]:
  30. pass
  31. class _InvalidDataAccessor(_DataAccessor):
  32. @staticmethod
  33. def get_supported_classes() -> t.List[str]:
  34. return [type(None).__name__]
  35. def get_data(
  36. self, guiApp: t.Any, var_name: str, value: t.Any, payload: t.Dict[str, t.Any], data_format: _DataFormat
  37. ) -> t.Dict[str, t.Any]:
  38. return {}
  39. def get_col_types(self, var_name: str, value: t.Any) -> t.Dict[str, str]:
  40. return {}
  41. class _DataAccessors(object):
  42. def __init__(self) -> None:
  43. self.__access_4_type: t.Dict[str, _DataAccessor] = {}
  44. self.__invalid_data_accessor = _InvalidDataAccessor()
  45. self.__data_format = _DataFormat.JSON
  46. from .array_dict_data_accessor import _ArrayDictDataAccessor
  47. from .numpy_data_accessor import _NumpyDataAccessor
  48. from .pandas_data_accessor import _PandasDataAccessor
  49. self._register(_PandasDataAccessor)
  50. self._register(_ArrayDictDataAccessor)
  51. self._register(_NumpyDataAccessor)
  52. def _register(self, cls: t.Type[_DataAccessor]) -> None:
  53. if not inspect.isclass(cls):
  54. raise AttributeError("The argument of 'DataAccessors.register' should be a class")
  55. if not issubclass(cls, _DataAccessor):
  56. raise TypeError(f"Class {cls.__name__} is not a subclass of DataAccessor")
  57. names = cls.get_supported_classes()
  58. if not names:
  59. raise TypeError(f"method {cls.__name__}.get_supported_classes returned an invalid value")
  60. # check existence
  61. inst: t.Optional[_DataAccessor] = None
  62. for name in names:
  63. inst = self.__access_4_type.get(name)
  64. if inst:
  65. break
  66. if inst is None:
  67. try:
  68. inst = cls()
  69. except Exception as e:
  70. raise TypeError(f"Class {cls.__name__} cannot be instantiated") from e
  71. if inst:
  72. for name in names:
  73. self.__access_4_type[name] = inst # type: ignore
  74. def __get_instance(self, value: _TaipyData) -> _DataAccessor: # type: ignore
  75. value = value.get()
  76. access = self.__access_4_type.get(type(value).__name__)
  77. if access is None:
  78. if value is not None:
  79. _warn(f"Can't find Data Accessor for type {type(value).__name__}.")
  80. return self.__invalid_data_accessor
  81. return access
  82. def _get_data(
  83. self, guiApp: t.Any, var_name: str, value: _TaipyData, payload: t.Dict[str, t.Any]
  84. ) -> t.Dict[str, t.Any]:
  85. return self.__get_instance(value).get_data(guiApp, var_name, value.get(), payload, self.__data_format)
  86. def _get_col_types(self, var_name: str, value: _TaipyData) -> t.Dict[str, str]:
  87. return self.__get_instance(value).get_col_types(var_name, value.get())
  88. def _set_data_format(self, data_format: _DataFormat):
  89. self.__data_format = data_format