_adapters.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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 math
  12. import typing as t
  13. from enum import Enum
  14. from numbers import Number
  15. import pandas as pd
  16. from taipy.core import (
  17. Cycle,
  18. DataNode,
  19. Job,
  20. Scenario,
  21. Sequence,
  22. Task,
  23. is_deletable,
  24. is_editable,
  25. is_promotable,
  26. is_readable,
  27. is_submittable,
  28. )
  29. from taipy.core import get as core_get
  30. from taipy.core.data._tabular_datanode_mixin import _TabularDataNodeMixin
  31. from taipy.gui._warnings import _warn
  32. from taipy.gui.gui import _DoNotUpdate
  33. from taipy.gui.utils import _TaipyBase
  34. # prevent gui from trying to push scenario instances to the front-end
  35. class _GCDoNotUpdate(_DoNotUpdate):
  36. def __repr__(self):
  37. return self.get_label() if hasattr(self, "get_label") else super().__repr__()
  38. Scenario.__bases__ += (_GCDoNotUpdate,)
  39. Sequence.__bases__ += (_GCDoNotUpdate,)
  40. DataNode.__bases__ += (_GCDoNotUpdate,)
  41. Cycle.__bases__ += (_GCDoNotUpdate,)
  42. Job.__bases__ += (_GCDoNotUpdate,)
  43. Task.__bases__ += (_GCDoNotUpdate,)
  44. class _EntityType(Enum):
  45. CYCLE = 0
  46. SCENARIO = 1
  47. SEQUENCE = 2
  48. DATANODE = 3
  49. class _GuiCoreScenarioAdapter(_TaipyBase):
  50. __INNER_PROPS = ["name"]
  51. def get(self):
  52. data = super().get()
  53. if isinstance(data, (list, tuple)) and len(data) == 1:
  54. data = data[0]
  55. if isinstance(data, Scenario):
  56. try:
  57. if scenario := core_get(data.id):
  58. return [
  59. scenario.id,
  60. scenario.is_primary,
  61. scenario.config_id,
  62. scenario.creation_date.isoformat(),
  63. scenario.cycle.get_simple_label() if scenario.cycle else "",
  64. scenario.get_simple_label(),
  65. list(scenario.tags) if scenario.tags else [],
  66. [
  67. (k, v)
  68. for k, v in scenario.properties.items()
  69. if k not in _GuiCoreScenarioAdapter.__INNER_PROPS
  70. ]
  71. if scenario.properties
  72. else [],
  73. [
  74. (
  75. s.get_simple_label(),
  76. [t.id for t in s.tasks.values()] if hasattr(s, "tasks") else [],
  77. is_submittable(s),
  78. is_editable(s),
  79. )
  80. for s in scenario.sequences.values()
  81. ]
  82. if hasattr(scenario, "sequences") and scenario.sequences
  83. else [],
  84. {t.id: t.get_simple_label() for t in scenario.tasks.values()}
  85. if hasattr(scenario, "tasks")
  86. else {},
  87. list(scenario.properties.get("authorized_tags", [])) if scenario.properties else [],
  88. is_deletable(scenario),
  89. is_promotable(scenario),
  90. is_submittable(scenario),
  91. is_readable(scenario),
  92. is_editable(scenario),
  93. ]
  94. except Exception as e:
  95. _warn(f"Access to scenario ({data.id if hasattr(data, 'id') else 'No_id'}) failed", e)
  96. return None
  97. @staticmethod
  98. def get_hash():
  99. return _TaipyBase._HOLDER_PREFIX + "Sc"
  100. class _GuiCoreScenarioDagAdapter(_TaipyBase):
  101. @staticmethod
  102. def get_entity_type(node: t.Any):
  103. return DataNode.__name__ if isinstance(node.entity, DataNode) else node.type
  104. def get(self):
  105. data = super().get()
  106. if isinstance(data, (list, tuple)) and len(data) == 1:
  107. data = data[0]
  108. if isinstance(data, Scenario):
  109. try:
  110. if scenario := core_get(data.id):
  111. dag = scenario._get_dag()
  112. nodes = {}
  113. for id, node in dag.nodes.items():
  114. entityType = _GuiCoreScenarioDagAdapter.get_entity_type(node)
  115. cat = nodes.get(entityType)
  116. if cat is None:
  117. cat = {}
  118. nodes[entityType] = cat
  119. cat[id] = {
  120. "name": node.entity.get_simple_label(),
  121. "type": node.entity.storage_type() if hasattr(node.entity, "storage_type") else None,
  122. }
  123. return [
  124. data.id,
  125. nodes,
  126. [
  127. (
  128. _GuiCoreScenarioDagAdapter.get_entity_type(e.src),
  129. e.src.entity.id,
  130. _GuiCoreScenarioDagAdapter.get_entity_type(e.dest),
  131. e.dest.entity.id,
  132. )
  133. for e in dag.edges
  134. ],
  135. ]
  136. except Exception as e:
  137. _warn(f"Access to scenario ({data.id if hasattr(data, 'id') else 'No_id'}) failed", e)
  138. return None
  139. @staticmethod
  140. def get_hash():
  141. return _TaipyBase._HOLDER_PREFIX + "ScG"
  142. class _GuiCoreScenarioNoUpdate(_TaipyBase, _DoNotUpdate):
  143. @staticmethod
  144. def get_hash():
  145. return _TaipyBase._HOLDER_PREFIX + "ScN"
  146. class _GuiCoreDatanodeAdapter(_TaipyBase):
  147. @staticmethod
  148. def _is_tabular_data(datanode: DataNode, value: t.Any):
  149. if isinstance(datanode, _TabularDataNodeMixin):
  150. return True
  151. if datanode.is_ready_for_reading:
  152. return isinstance(value, (pd.DataFrame, pd.Series, list, tuple, dict))
  153. return False
  154. def __get_data(self, dn: DataNode):
  155. if dn._last_edit_date:
  156. if isinstance(dn, _TabularDataNodeMixin):
  157. return (None, None, True, None)
  158. try:
  159. value = dn.read()
  160. if _GuiCoreDatanodeAdapter._is_tabular_data(dn, value):
  161. return (None, None, True, None)
  162. val_type = (
  163. "date"
  164. if "date" in type(value).__name__
  165. else type(value).__name__
  166. if isinstance(value, Number)
  167. else None
  168. )
  169. if isinstance(value, float):
  170. if math.isnan(value):
  171. value = None
  172. return (
  173. value,
  174. val_type,
  175. None,
  176. None,
  177. )
  178. except Exception as e:
  179. return (None, None, None, f"read data_node: {e}")
  180. return (None, None, None, f"Data unavailable for {dn.get_simple_label()}")
  181. def get(self):
  182. data = super().get()
  183. if isinstance(data, (list, tuple)) and len(data) == 1:
  184. data = data[0]
  185. if isinstance(data, DataNode):
  186. try:
  187. if datanode := core_get(data.id):
  188. owner = core_get(datanode.owner_id) if datanode.owner_id else None
  189. return [
  190. datanode.id,
  191. datanode.storage_type() if hasattr(datanode, "storage_type") else "",
  192. datanode.config_id,
  193. f"{datanode.last_edit_date}" if datanode.last_edit_date else "",
  194. f"{datanode.expiration_date}" if datanode.last_edit_date else "",
  195. datanode.get_simple_label(),
  196. datanode.owner_id or "",
  197. owner.get_simple_label() if owner else "GLOBAL",
  198. _EntityType.CYCLE.value
  199. if isinstance(owner, Cycle)
  200. else _EntityType.SCENARIO.value
  201. if isinstance(owner, Scenario)
  202. else -1,
  203. self.__get_data(datanode),
  204. datanode._edit_in_progress,
  205. datanode._editor_id,
  206. is_readable(datanode),
  207. is_editable(datanode),
  208. ]
  209. except Exception as e:
  210. _warn(f"Access to datanode ({data.id if hasattr(data, 'id') else 'No_id'}) failed", e)
  211. return None
  212. @staticmethod
  213. def get_hash():
  214. return _TaipyBase._HOLDER_PREFIX + "Dn"