test_data_node.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  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 os
  12. from datetime import datetime, timedelta
  13. from time import sleep
  14. from unittest import mock
  15. import pytest
  16. import taipy.core as tp
  17. from taipy.common.config import Config
  18. from taipy.common.config.common.scope import Scope
  19. from taipy.common.config.exceptions.exceptions import InvalidConfigurationId
  20. from taipy.core.data._data_manager import _DataManager
  21. from taipy.core.data._data_manager_factory import _DataManagerFactory
  22. from taipy.core.data.data_node import DataNode
  23. from taipy.core.data.data_node_id import DataNodeId
  24. from taipy.core.data.in_memory import InMemoryDataNode
  25. from taipy.core.exceptions.exceptions import DataNodeIsBeingEdited, NoData
  26. from taipy.core.job.job_id import JobId
  27. from taipy.core.task.task import Task
  28. from .utils import FakeDataNode
  29. def funct_a_b(input: str):
  30. print("task_a_b") # noqa: T201
  31. return "B"
  32. def funct_b_c(input: str):
  33. print("task_b_c") # noqa: T201
  34. return "C"
  35. def funct_b_d(input: str):
  36. print("task_b_d") # noqa: T201
  37. return "D"
  38. class TestDataNode:
  39. def test_dn_equals(self, data_node):
  40. data_manager = _DataManagerFactory()._build_manager()
  41. dn_id = data_node.id
  42. data_manager._set(data_node)
  43. # # To test if instance is same type
  44. task = Task("task", {}, print, [], [], dn_id)
  45. dn_2 = data_manager._get(dn_id)
  46. assert data_node == dn_2
  47. assert data_node != dn_id
  48. assert data_node != task
  49. def test_create_with_default_values(self):
  50. dn = DataNode("foo_bar")
  51. assert dn.config_id == "foo_bar"
  52. assert dn.scope == Scope.SCENARIO
  53. assert dn.id is not None
  54. assert dn.name is None
  55. assert dn.owner_id is None
  56. assert dn.parent_ids == set()
  57. assert dn.last_edit_date is None
  58. assert dn.job_ids == []
  59. assert not dn.is_ready_for_reading
  60. assert len(dn.properties) == 0
  61. def test_is_up_to_date_when_not_written(self):
  62. dn_confg_1 = Config.configure_in_memory_data_node("dn_1", default_data="a")
  63. dn_confg_2 = Config.configure_in_memory_data_node("dn_2")
  64. task_config_1 = Config.configure_task("t1", funct_a_b, [dn_confg_1], [dn_confg_2])
  65. scenario_config = Config.configure_scenario("sc", [task_config_1])
  66. scenario = tp.create_scenario(scenario_config)
  67. assert scenario.dn_1.is_up_to_date is True
  68. assert scenario.dn_2.is_up_to_date is False
  69. tp.submit(scenario)
  70. assert scenario.dn_1.is_up_to_date is True
  71. assert scenario.dn_2.is_up_to_date is True
  72. def test_create(self):
  73. a_date = datetime.now()
  74. dn = DataNode(
  75. "foo_bar",
  76. Scope.SCENARIO,
  77. DataNodeId("an_id"),
  78. "a_scenario_id",
  79. {"a_parent_id"},
  80. a_date,
  81. [{"job_id": "a_job_id"}],
  82. edit_in_progress=False,
  83. prop="erty",
  84. name="a name",
  85. )
  86. assert dn.config_id == "foo_bar"
  87. assert dn.scope == Scope.SCENARIO
  88. assert dn.id == "an_id"
  89. assert dn.name == "a name"
  90. assert dn.owner_id == "a_scenario_id"
  91. assert dn.parent_ids == {"a_parent_id"}
  92. assert dn.last_edit_date == a_date
  93. assert dn.job_ids == ["a_job_id"]
  94. assert dn.is_ready_for_reading
  95. assert len(dn.properties) == 2
  96. assert dn.properties == {"prop": "erty", "name": "a name"}
  97. with pytest.raises(InvalidConfigurationId):
  98. DataNode("foo bar")
  99. def test_read_write(self):
  100. dn = FakeDataNode("foo_bar")
  101. with pytest.raises(NoData):
  102. assert dn.read() is None
  103. dn.read_or_raise()
  104. assert dn.write_has_been_called == 0
  105. assert dn.read_has_been_called == 0
  106. assert not dn.is_ready_for_reading
  107. assert dn.last_edit_date is None
  108. assert dn.job_ids == []
  109. assert dn.edits == []
  110. dn.write("Any data")
  111. assert dn.write_has_been_called == 1
  112. assert dn.read_has_been_called == 0
  113. assert dn.last_edit_date is not None
  114. first_edition = dn.last_edit_date
  115. assert dn.is_ready_for_reading
  116. assert dn.job_ids == []
  117. assert len(dn.edits) == 1
  118. assert dn.get_last_edit()["timestamp"] == dn.last_edit_date
  119. sleep(0.1)
  120. dn.write("Any other data", job_id := JobId("a_job_id"))
  121. assert dn.write_has_been_called == 2
  122. assert dn.read_has_been_called == 0
  123. second_edition = dn.last_edit_date
  124. assert first_edition < second_edition
  125. assert dn.is_ready_for_reading
  126. assert dn.job_ids == [job_id]
  127. assert len(dn.edits) == 2
  128. assert dn.get_last_edit()["timestamp"] == dn.last_edit_date
  129. dn.read()
  130. assert dn.write_has_been_called == 2
  131. assert dn.read_has_been_called == 1
  132. second_edition = dn.last_edit_date
  133. assert first_edition < second_edition
  134. assert dn.is_ready_for_reading
  135. assert dn.job_ids == [job_id]
  136. def test_lock_initialization(self):
  137. dn = InMemoryDataNode("dn", Scope.SCENARIO)
  138. assert not dn.edit_in_progress
  139. assert dn._editor_id is None
  140. assert dn._editor_expiration_date is None
  141. def test_locked_dn_unlockable_only_by_same_editor(self):
  142. dn = InMemoryDataNode("dn", Scope.SCENARIO)
  143. dn.lock_edit("user_1")
  144. assert dn.edit_in_progress
  145. assert dn._editor_id == "user_1"
  146. assert dn._editor_expiration_date is not None
  147. with pytest.raises(DataNodeIsBeingEdited):
  148. dn.lock_edit("user_2")
  149. with pytest.raises(DataNodeIsBeingEdited):
  150. dn.unlock_edit("user_2")
  151. dn.unlock_edit("user_1")
  152. assert not dn.edit_in_progress
  153. assert dn._editor_id is None
  154. assert dn._editor_expiration_date is None
  155. def test_none_editor_can_lock_a_locked_dn(self):
  156. dn = InMemoryDataNode("dn", Scope.SCENARIO)
  157. dn.lock_edit("user")
  158. assert dn.edit_in_progress
  159. assert dn._editor_id == "user"
  160. assert dn._editor_expiration_date is not None
  161. dn.lock_edit()
  162. assert dn.edit_in_progress
  163. assert dn._editor_id is None
  164. assert dn._editor_expiration_date is None
  165. def test_none_editor_can_unlock_a_locked_dn(self):
  166. dn = InMemoryDataNode("dn", Scope.SCENARIO)
  167. dn.lock_edit("user")
  168. assert dn.edit_in_progress
  169. assert dn._editor_id == "user"
  170. assert dn._editor_expiration_date is not None
  171. dn.unlock_edit()
  172. assert not dn.edit_in_progress
  173. assert dn._editor_id is None
  174. assert dn._editor_expiration_date is None
  175. dn.lock_edit()
  176. assert dn.edit_in_progress
  177. assert dn._editor_id is None
  178. assert dn._editor_expiration_date is None
  179. dn.unlock_edit()
  180. assert not dn.edit_in_progress
  181. assert dn._editor_id is None
  182. assert dn._editor_expiration_date is None
  183. def test_ready_for_reading(self):
  184. dn = InMemoryDataNode("foo_bar", Scope.CYCLE)
  185. assert dn.last_edit_date is None
  186. assert not dn.is_ready_for_reading
  187. assert dn.job_ids == []
  188. dn.lock_edit()
  189. assert dn.last_edit_date is None
  190. assert not dn.is_ready_for_reading
  191. assert dn.job_ids == []
  192. dn.unlock_edit()
  193. assert dn.last_edit_date is None
  194. assert not dn.is_ready_for_reading
  195. assert dn.job_ids == []
  196. dn.lock_edit()
  197. assert dn.last_edit_date is None
  198. assert not dn.is_ready_for_reading
  199. assert dn.job_ids == []
  200. dn.write("toto", job_id := JobId("a_job_id"))
  201. assert dn.last_edit_date is not None
  202. assert dn.is_ready_for_reading
  203. assert dn.job_ids == [job_id]
  204. def test_is_valid_no_validity_period(self):
  205. # Test Never been written
  206. dn = InMemoryDataNode("foo", Scope.SCENARIO, DataNodeId("id"), "name", "owner_id")
  207. assert not dn.is_valid
  208. # test has been written
  209. dn.write("My data")
  210. assert dn.is_valid
  211. def test_is_valid_with_30_min_validity_period(self):
  212. # Test Never been written
  213. dn = InMemoryDataNode(
  214. "foo", Scope.SCENARIO, DataNodeId("id"), "name", "owner_id", validity_period=timedelta(minutes=30)
  215. )
  216. assert dn.is_valid is False
  217. # Has been written less than 30 minutes ago
  218. dn.write("My data")
  219. assert dn.is_valid is True
  220. # Has been written more than 30 minutes ago
  221. dn.last_edit_date = datetime.now() + timedelta(days=-1)
  222. assert dn.is_valid is False
  223. def test_is_valid_with_5_days_validity_period(self):
  224. # Test Never been written
  225. dn = InMemoryDataNode("foo", Scope.SCENARIO, validity_period=timedelta(days=5))
  226. assert dn.is_valid is False
  227. # Has been written less than 30 minutes ago
  228. dn.write("My data")
  229. assert dn.is_valid is True
  230. # Has been written more than 30 minutes ago
  231. dn._last_edit_date = datetime.now() - timedelta(days=6)
  232. _DataManager()._set(dn)
  233. assert dn.is_valid is False
  234. def test_is_up_to_date(self, current_datetime):
  235. dn_confg_1 = Config.configure_in_memory_data_node("dn_1")
  236. dn_confg_2 = Config.configure_in_memory_data_node("dn_2")
  237. dn_confg_3 = Config.configure_in_memory_data_node("dn_3", scope=Scope.GLOBAL)
  238. task_config_1 = Config.configure_task("t1", print, [dn_confg_1], [dn_confg_2])
  239. task_config_2 = Config.configure_task("t2", print, [dn_confg_2], [dn_confg_3])
  240. scenario_config = Config.configure_scenario("sc", [task_config_1, task_config_2])
  241. scenario_1 = tp.create_scenario(scenario_config)
  242. assert len(_DataManager._get_all()) == 3
  243. dn_1_1 = scenario_1.data_nodes["dn_1"]
  244. dn_2_1 = scenario_1.data_nodes["dn_2"]
  245. dn_3_1 = scenario_1.data_nodes["dn_3"]
  246. assert dn_1_1.last_edit_date is None
  247. assert dn_2_1.last_edit_date is None
  248. assert dn_3_1.last_edit_date is None
  249. dn_1_1.last_edit_date = current_datetime + timedelta(1)
  250. dn_2_1.last_edit_date = current_datetime + timedelta(2)
  251. dn_3_1.last_edit_date = current_datetime + timedelta(3)
  252. assert dn_1_1.is_up_to_date
  253. assert dn_2_1.is_up_to_date
  254. assert dn_3_1.is_up_to_date
  255. dn_2_1.last_edit_date = current_datetime + timedelta(4)
  256. assert dn_1_1.is_up_to_date
  257. assert dn_2_1.is_up_to_date
  258. assert not dn_3_1.is_up_to_date
  259. dn_1_1.last_edit_date = current_datetime + timedelta(5)
  260. assert dn_1_1.is_up_to_date
  261. assert not dn_2_1.is_up_to_date
  262. assert not dn_3_1.is_up_to_date
  263. dn_1_1.last_edit_date = current_datetime + timedelta(1)
  264. dn_2_1.last_edit_date = current_datetime + timedelta(2)
  265. dn_3_1.last_edit_date = current_datetime + timedelta(3)
  266. def test_is_up_to_date_across_scenarios(self, current_datetime):
  267. dn_confg_1 = Config.configure_in_memory_data_node("dn_1", scope=Scope.SCENARIO)
  268. dn_confg_2 = Config.configure_in_memory_data_node("dn_2", scope=Scope.SCENARIO)
  269. dn_confg_3 = Config.configure_in_memory_data_node("dn_3", scope=Scope.GLOBAL)
  270. task_config_1 = Config.configure_task("t1", print, [dn_confg_1], [dn_confg_2])
  271. task_config_2 = Config.configure_task("t2", print, [dn_confg_2], [dn_confg_3])
  272. scenario_config = Config.configure_scenario("sc", [task_config_1, task_config_2])
  273. scenario_1 = tp.create_scenario(scenario_config)
  274. scenario_2 = tp.create_scenario(scenario_config)
  275. assert len(_DataManager._get_all()) == 5
  276. dn_1_1 = scenario_1.data_nodes["dn_1"]
  277. dn_2_1 = scenario_1.data_nodes["dn_2"]
  278. dn_1_2 = scenario_2.data_nodes["dn_1"]
  279. dn_2_2 = scenario_2.data_nodes["dn_2"]
  280. dn_3 = scenario_1.data_nodes["dn_3"]
  281. assert dn_3 == scenario_2.data_nodes["dn_3"]
  282. assert dn_1_1.last_edit_date is None
  283. assert dn_2_1.last_edit_date is None
  284. assert dn_1_2.last_edit_date is None
  285. assert dn_2_2.last_edit_date is None
  286. assert dn_3.last_edit_date is None
  287. dn_1_1.last_edit_date = current_datetime + timedelta(1)
  288. dn_2_1.last_edit_date = current_datetime + timedelta(2)
  289. dn_1_2.last_edit_date = current_datetime + timedelta(3)
  290. dn_2_2.last_edit_date = current_datetime + timedelta(4)
  291. dn_3.last_edit_date = current_datetime + timedelta(5)
  292. assert dn_1_1.is_up_to_date
  293. assert dn_2_1.is_up_to_date
  294. assert dn_1_2.is_up_to_date
  295. assert dn_2_2.is_up_to_date
  296. assert dn_3.is_up_to_date
  297. dn_2_1.last_edit_date = current_datetime + timedelta(6)
  298. assert dn_1_1.is_up_to_date
  299. assert dn_2_1.is_up_to_date
  300. assert dn_1_2.is_up_to_date
  301. assert dn_2_2.is_up_to_date
  302. assert not dn_3.is_up_to_date
  303. dn_2_1.last_edit_date = current_datetime + timedelta(2)
  304. dn_2_2.last_edit_date = current_datetime + timedelta(6)
  305. assert dn_1_1.is_up_to_date
  306. assert dn_2_1.is_up_to_date
  307. assert dn_1_2.is_up_to_date
  308. assert dn_2_2.is_up_to_date
  309. assert not dn_3.is_up_to_date
  310. dn_2_2.last_edit_date = current_datetime + timedelta(4)
  311. dn_1_1.last_edit_date = current_datetime + timedelta(6)
  312. assert dn_1_1.is_up_to_date
  313. assert not dn_2_1.is_up_to_date
  314. assert dn_1_2.is_up_to_date
  315. assert dn_2_2.is_up_to_date
  316. assert not dn_3.is_up_to_date
  317. dn_1_2.last_edit_date = current_datetime + timedelta(6)
  318. assert dn_1_1.is_up_to_date
  319. assert not dn_2_1.is_up_to_date
  320. assert dn_1_2.is_up_to_date
  321. assert not dn_2_2.is_up_to_date
  322. assert not dn_3.is_up_to_date
  323. def test_do_not_recompute_data_node_valid_but_continue_sequence_execution(self):
  324. a = Config.configure_data_node("A", "pickle", default_data="A")
  325. b = Config.configure_data_node("B", "pickle")
  326. c = Config.configure_data_node("C", "pickle")
  327. d = Config.configure_data_node("D", "pickle")
  328. task_a_b = Config.configure_task("task_a_b", funct_a_b, input=a, output=b, skippable=True)
  329. task_b_c = Config.configure_task("task_b_c", funct_b_c, input=b, output=c)
  330. task_b_d = Config.configure_task("task_b_d", funct_b_d, input=b, output=d)
  331. scenario_cfg = Config.configure_scenario("scenario", [task_a_b, task_b_c, task_b_d])
  332. scenario = tp.create_scenario(scenario_cfg)
  333. scenario.submit()
  334. assert scenario.A.read() == "A"
  335. assert scenario.B.read() == "B"
  336. assert scenario.C.read() == "C"
  337. assert scenario.D.read() == "D"
  338. scenario.submit()
  339. assert len(tp.get_jobs()) == 6
  340. jobs_and_status = [(job.task.config_id, job.status) for job in tp.get_jobs()]
  341. assert ("task_a_b", tp.Status.COMPLETED) in jobs_and_status
  342. assert ("task_a_b", tp.Status.SKIPPED) in jobs_and_status
  343. assert ("task_b_c", tp.Status.COMPLETED) in jobs_and_status
  344. assert ("task_b_d", tp.Status.COMPLETED) in jobs_and_status
  345. def test_data_node_update_after_writing(self):
  346. dn = FakeDataNode("foo")
  347. _DataManager._set(dn)
  348. assert not _DataManager._get(dn.id).is_ready_for_reading
  349. dn.write("Any data")
  350. assert dn.is_ready_for_reading
  351. assert _DataManager._get(dn.id).is_ready_for_reading
  352. def test_expiration_date_raise_if_never_write(self):
  353. dn = FakeDataNode("foo")
  354. with pytest.raises(NoData):
  355. _ = dn.expiration_date
  356. def test_validity_null_if_never_write(self):
  357. dn = FakeDataNode("foo")
  358. assert dn.validity_period is None
  359. def test_auto_set_and_reload(self, current_datetime):
  360. dn_1 = InMemoryDataNode(
  361. "foo",
  362. scope=Scope.GLOBAL,
  363. id=DataNodeId("an_id"),
  364. owner_id=None,
  365. parent_ids=None,
  366. last_edit_date=current_datetime,
  367. edits=[{"job_id": "a_job_id"}],
  368. edit_in_progress=False,
  369. validity_period=None,
  370. properties={
  371. "name": "foo",
  372. },
  373. )
  374. dm = _DataManager()
  375. dm._set(dn_1)
  376. dn_2 = dm._get(dn_1)
  377. # auto set & reload on scope attribute
  378. assert dn_1.scope == Scope.GLOBAL
  379. assert dn_2.scope == Scope.GLOBAL
  380. dn_1.scope = Scope.CYCLE
  381. assert dn_1.scope == Scope.CYCLE
  382. assert dn_2.scope == Scope.CYCLE
  383. dn_2.scope = Scope.SCENARIO
  384. assert dn_1.scope == Scope.SCENARIO
  385. assert dn_2.scope == Scope.SCENARIO
  386. new_datetime = current_datetime + timedelta(1)
  387. new_datetime_1 = current_datetime + timedelta(3)
  388. # auto set & reload on last_edit_date attribute
  389. assert dn_1.last_edit_date == current_datetime
  390. assert dn_2.last_edit_date == current_datetime
  391. dn_1.last_edit_date = new_datetime_1
  392. assert dn_1.last_edit_date == new_datetime_1
  393. assert dn_2.last_edit_date == new_datetime_1
  394. dn_2.last_edit_date = new_datetime
  395. assert dn_1.last_edit_date == new_datetime
  396. assert dn_2.last_edit_date == new_datetime
  397. # auto set & reload on name attribute
  398. assert dn_1.name == "foo"
  399. assert dn_2.name == "foo"
  400. dn_1.name = "fed"
  401. assert dn_1.name == "fed"
  402. assert dn_2.name == "fed"
  403. dn_2.name = "def"
  404. assert dn_1.name == "def"
  405. assert dn_2.name == "def"
  406. # auto set & reload on parent_ids attribute (set() object does not have auto set yet)
  407. assert dn_1.parent_ids == set()
  408. assert dn_2.parent_ids == set()
  409. dn_1._parent_ids.update(["sc2"])
  410. _DataManager._set(dn_1)
  411. assert dn_1.parent_ids == {"sc2"}
  412. assert dn_2.parent_ids == {"sc2"}
  413. dn_2._parent_ids.clear()
  414. dn_2._parent_ids.update(["sc1"])
  415. _DataManager._set(dn_2)
  416. assert dn_1.parent_ids == {"sc1"}
  417. assert dn_2.parent_ids == {"sc1"}
  418. dn_2._parent_ids.clear()
  419. _DataManager._set(dn_2)
  420. # auto set & reload on edit_in_progress attribute
  421. assert not dn_2.edit_in_progress
  422. assert not dn_1.edit_in_progress
  423. dn_1.edit_in_progress = True
  424. assert dn_1.edit_in_progress
  425. assert dn_2.edit_in_progress
  426. dn_2.unlock_edit()
  427. assert not dn_1.edit_in_progress
  428. assert not dn_2.edit_in_progress
  429. dn_1.lock_edit()
  430. assert dn_1.edit_in_progress
  431. assert dn_2.edit_in_progress
  432. # auto set & reload on validity_period attribute
  433. time_period_1 = timedelta(1)
  434. time_period_2 = timedelta(5)
  435. assert dn_1.validity_period is None
  436. assert dn_2.validity_period is None
  437. dn_1.validity_period = time_period_1
  438. assert dn_1.validity_period == time_period_1
  439. assert dn_2.validity_period == time_period_1
  440. dn_2.validity_period = time_period_2
  441. assert dn_1.validity_period == time_period_2
  442. assert dn_2.validity_period == time_period_2
  443. dn_1.last_edit_date = new_datetime
  444. assert len(dn_1.job_ids) == 1
  445. assert len(dn_2.job_ids) == 1
  446. with dn_1 as dn:
  447. assert dn.config_id == "foo"
  448. assert dn.owner_id is None
  449. assert dn.scope == Scope.SCENARIO
  450. assert dn.last_edit_date == new_datetime
  451. assert dn.name == "def"
  452. assert dn.edit_in_progress
  453. assert dn.validity_period == time_period_2
  454. assert len(dn.job_ids) == 1
  455. assert dn._is_in_context
  456. new_datetime_2 = new_datetime + timedelta(5)
  457. dn.scope = Scope.CYCLE
  458. dn.last_edit_date = new_datetime_2
  459. dn.name = "abc"
  460. dn.edit_in_progress = False
  461. dn.validity_period = None
  462. assert dn.config_id == "foo"
  463. assert dn.owner_id is None
  464. assert dn.scope == Scope.SCENARIO
  465. assert dn.last_edit_date == new_datetime
  466. assert dn.name == "def"
  467. assert dn.edit_in_progress
  468. assert dn.validity_period == time_period_2
  469. assert len(dn.job_ids) == 1
  470. assert dn_1.config_id == "foo"
  471. assert dn_1.owner_id is None
  472. assert dn_1.scope == Scope.CYCLE
  473. assert dn_1.last_edit_date == new_datetime_2
  474. assert dn_1.name == "abc"
  475. assert not dn_1.edit_in_progress
  476. assert dn_1.validity_period is None
  477. assert not dn_1._is_in_context
  478. assert len(dn_1.job_ids) == 1
  479. def test_auto_set_and_reload_properties(self):
  480. dn_1 = InMemoryDataNode("foo", scope=Scope.GLOBAL, properties={"name": "def"})
  481. dm = _DataManager()
  482. dm._set(dn_1)
  483. dn_2 = dm._get(dn_1)
  484. # auto set & reload on properties attribute
  485. assert dn_1.properties == {"name": "def"}
  486. assert dn_2.properties == {"name": "def"}
  487. dn_1._properties["qux"] = 4
  488. assert dn_1.properties["qux"] == 4
  489. assert dn_2.properties["qux"] == 4
  490. assert dn_1.properties == {"qux": 4, "name": "def"}
  491. assert dn_2.properties == {"qux": 4, "name": "def"}
  492. dn_2._properties["qux"] = 5
  493. assert dn_1.properties["qux"] == 5
  494. assert dn_2.properties["qux"] == 5
  495. dn_1.properties["temp_key_1"] = "temp_value_1"
  496. dn_1.properties["temp_key_2"] = "temp_value_2"
  497. assert dn_1.properties == {
  498. "name": "def",
  499. "qux": 5,
  500. "temp_key_1": "temp_value_1",
  501. "temp_key_2": "temp_value_2",
  502. }
  503. assert dn_2.properties == {"name": "def", "qux": 5, "temp_key_1": "temp_value_1", "temp_key_2": "temp_value_2"}
  504. dn_1.properties.pop("temp_key_1")
  505. assert "temp_key_1" not in dn_1.properties.keys()
  506. assert "temp_key_1" not in dn_1.properties.keys()
  507. assert dn_1.properties == {"name": "def", "qux": 5, "temp_key_2": "temp_value_2"}
  508. assert dn_2.properties == {"name": "def", "qux": 5, "temp_key_2": "temp_value_2"}
  509. dn_2.properties.pop("temp_key_2")
  510. assert dn_1.properties == {"qux": 5, "name": "def"}
  511. assert dn_2.properties == {"qux": 5, "name": "def"}
  512. assert "temp_key_2" not in dn_1.properties.keys()
  513. assert "temp_key_2" not in dn_2.properties.keys()
  514. dn_1.properties["temp_key_3"] = 0
  515. assert dn_1.properties == {"qux": 5, "temp_key_3": 0, "name": "def"}
  516. assert dn_2.properties == {"qux": 5, "temp_key_3": 0, "name": "def"}
  517. dn_1.properties.update({"temp_key_3": 1})
  518. assert dn_1.properties == {"qux": 5, "temp_key_3": 1, "name": "def"}
  519. assert dn_2.properties == {"qux": 5, "temp_key_3": 1, "name": "def"}
  520. dn_1.properties.update({})
  521. assert dn_1.properties == {"qux": 5, "temp_key_3": 1, "name": "def"}
  522. assert dn_2.properties == {"qux": 5, "temp_key_3": 1, "name": "def"}
  523. dn_1.properties["temp_key_4"] = 0
  524. dn_1.properties["temp_key_5"] = 0
  525. with dn_1 as dn:
  526. assert dn._is_in_context
  527. assert dn.properties["qux"] == 5
  528. assert dn.properties["temp_key_3"] == 1
  529. assert dn.properties["temp_key_4"] == 0
  530. assert dn.properties["temp_key_5"] == 0
  531. dn.properties["qux"] = 9
  532. dn.properties.pop("temp_key_3")
  533. dn.properties.pop("temp_key_4")
  534. dn.properties.update({"temp_key_4": 1})
  535. dn.properties.update({"temp_key_5": 2})
  536. dn.properties.pop("temp_key_5")
  537. dn.properties.update({})
  538. assert dn.properties["qux"] == 5
  539. assert dn.properties["temp_key_3"] == 1
  540. assert dn.properties["temp_key_4"] == 0
  541. assert dn.properties["temp_key_5"] == 0
  542. assert not dn_1._is_in_context
  543. assert dn_1.properties["qux"] == 9
  544. assert "temp_key_3" not in dn_1.properties.keys()
  545. assert dn_1.properties["temp_key_4"] == 1
  546. assert "temp_key_5" not in dn_1.properties.keys()
  547. def test_get_parents(self, data_node):
  548. with mock.patch("taipy.core.get_parents") as mck:
  549. data_node.get_parents()
  550. mck.assert_called_once_with(data_node)
  551. def test_data_node_with_env_variable_value_not_stored(self):
  552. dn_config = Config.configure_data_node("A", prop="ENV[FOO]")
  553. with mock.patch.dict(os.environ, {"FOO": "bar"}):
  554. dn = _DataManager._bulk_get_or_create([dn_config])[dn_config]
  555. assert dn._properties.data["prop"] == "ENV[FOO]"
  556. assert dn.properties["prop"] == "bar"
  557. def test_path_populated_with_config_default_path(self):
  558. dn_config = Config.configure_data_node("data_node", "pickle", default_path="foo.p")
  559. assert dn_config.default_path == "foo.p"
  560. data_node = _DataManager._bulk_get_or_create([dn_config])[dn_config]
  561. assert data_node.path == "foo.p"
  562. data_node.path = "baz.p"
  563. assert data_node.path == "baz.p"
  564. def test_edit_edit_tracking(self):
  565. dn_config = Config.configure_data_node("A")
  566. data_node = _DataManager._bulk_get_or_create([dn_config])[dn_config]
  567. data_node.write(data="1", job_id="job_1")
  568. data_node.write(data="2", job_id="job_1")
  569. data_node.write(data="3", job_id="job_1")
  570. assert len(data_node.edits) == 3
  571. assert len(data_node.job_ids) == 3
  572. assert data_node.edits[-1] == data_node.get_last_edit()
  573. assert data_node.last_edit_date == data_node.get_last_edit().get("timestamp")
  574. date = datetime(2050, 1, 1, 12, 12)
  575. data_node.write(data="4", timestamp=date, message="This is a comment on this edit", env="staging")
  576. assert len(data_node.edits) == 4
  577. assert len(data_node.job_ids) == 3
  578. assert data_node.edits[-1] == data_node.get_last_edit()
  579. last_edit = data_node.get_last_edit()
  580. assert last_edit["message"] == "This is a comment on this edit"
  581. assert last_edit["env"] == "staging"
  582. assert last_edit["timestamp"] == date
  583. def test_label(self):
  584. a_date = datetime.now()
  585. dn = DataNode(
  586. "foo_bar",
  587. Scope.SCENARIO,
  588. DataNodeId("an_id"),
  589. "a_scenario_id",
  590. {"a_parent_id"},
  591. a_date,
  592. [{"job_id": "a_job_id"}],
  593. edit_in_progress=False,
  594. prop="erty",
  595. name="a name",
  596. )
  597. with mock.patch("taipy.core.get") as get_mck:
  598. class MockOwner:
  599. label = "owner_label"
  600. def get_label(self):
  601. return self.label
  602. get_mck.return_value = MockOwner()
  603. assert dn.get_label() == "owner_label > " + dn.name
  604. assert dn.get_simple_label() == dn.name
  605. def test_explicit_label(self):
  606. a_date = datetime.now()
  607. dn = DataNode(
  608. "foo_bar",
  609. Scope.SCENARIO,
  610. DataNodeId("an_id"),
  611. "a_scenario_id",
  612. {"a_parent_id"},
  613. a_date,
  614. [{"job_id": "a_job_id"}],
  615. edit_in_progress=False,
  616. label="a label",
  617. name="a name",
  618. )
  619. assert dn.get_label() == "a label"
  620. assert dn.get_simple_label() == "a label"
  621. def test_change_data_node_name(self):
  622. cgf = Config.configure_data_node("foo", scope=Scope.GLOBAL)
  623. dn = tp.create_global_data_node(cgf)
  624. dn.name = "bar"
  625. assert dn.name == "bar"
  626. # This new syntax will be the only one allowed: https://github.com/Avaiga/taipy-core/issues/806
  627. dn.properties["name"] = "baz"
  628. assert dn.name == "baz"